EF 4.0 Dynamic Proxies POCO Object Does not match target type - entity-framework

I am using EF 4.0 and POCO's. I stumbled across this error while inserting to records into the data base.
Property accessor 'QualityReasonID' on object 'BI.Entities.QualityReason' threw the following exception:'Object does not match target type.'
There errors occur on the Databind to a GridView after saving a new record to the database. I identified what is happening but I am not sure WHY it is occurring or If I am using EF/POCO's incorrectly. Any insight would be appreciated.
The exception is occuring because the object types in the IEnumerable are not the same.
The orginal entrys in the table are of type System.Data.Entity.DynamicProxies.QualityReason_E483AD567288B459706092F1825F53B1F93C65C5329F8095DD1D848B5D039F04}
While the new one is BI.Entities.QuailtyReason.
Here is how I insert the new object.
public void createQualityReason(QualityReason qReasons)
{
dbcontext.QualityReasons.AddObject(qReasons);
dbcontext.SaveChanges();
}
I resolved the error by changing the fetch code from:
public IEnumerable<QualityReason> fetchQualityReasons()
{
IEnumerable<QualityReason> queryReasons = dbcontext.QualityReasons.AsEnumerable();
return queryReasons;
}
to
public IEnumerable<QualityReason> fetchQualityReasons()
{
IEnumerable<QualityReason> queryReasons = from data in dbcontext.QualityReasons.AsEnumerable()
select new QualityReason
{
QualityReasonID = data.QualityReasonID,
QualityReasonName = data.QualityReasonName
};
return queryReasons;
}
So to get around the error I have to select into the POCO class explicitly each time. This feels like I am going something wrong. Any thoughts?

The error is caused because GridView does not handle polymorphic datasources when using boundfields. So you have two options
Use TemplateFields instead which can handle polymorphic datasources, this may changing some of your front end code and GridView events.
Use Linq to create a non-polymorphic databsource that the boundfields can handle
So instead of using something like ti
gvGroups.DataSource = ProductHelper.Get()
gvGroups.DataBind();
var query = from p in ProductHelper.Get()
select new {p.ProductId, p.ProductName, p.ProductDesc, p.ProductLink};
gvGroups.DataSource = query;
gvGroups.DataBind();

I don't know if the problem has been solved yet, but I've had the same problem with my (POCO) "Scenario" class.
The problem disappeared when using a context.CreateObject<Scenario> to create the (POCO) object i.s.o. a .... = new Scenario().

Faced the same issue today and used Value Injecter to solve it. It's as simple as:
var dynamicProxyMember = _repository.FindOne<Member>(m=>m.Id = 1);
var member = new Member().InjectFrom(dynamicProxyMember) as Member;
That's it :)

Related

EF Core 2.0: How to discover the exact object, in object graph, causing error in a insert operation?

I have a complex and big object graph that I want to insert in database by using a DbContext and SaveChanges method.
This object is a result of parsing a text file with 40k lines (around 3MB of data). Some collections inside this object have thousands of items.
I am able to parse the file correctly and add it to the context so that it can start tracking the object. But when I try to SaveChanges, it says:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: String or binary data would be truncated.
I would like to know if there is a smart and efficient way of discovering which object is causing the issue. It seems that a varchar field is too little to store the data. But it's a lot of tables and fields to check manually.
I would like to get a more specific error somehow. I already configured an ILoggerProvider and added the EnableSensitiveDataLogging option in my dbContext to be able to see which sql queries are being generated. I even added MiniProfiler to be able to see the parameter values, because they are not present in the log generated by the dbContext.
Reading somewhere in the web, I found out that in EF6 there is some validation that happens before the sql is passed to the database to be executed. But it seems that in EF Core this is not available anymore. So how can I solve this?
After some research, the only approach I've found to solve this, is implementing some validation by overriding dbContext's SaveChanges method. I've made a merge of these two approaches to build mine:
Implementing Missing Features in Entity Framework Core - Part 3
Validation in EF Core
The result is...
ApplicationDbContext.cs
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
ValidateEntities();
return base.SaveChanges(acceptAllChangesOnSuccess);
}
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken())
{
ValidateEntities();
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
private void ValidateEntities()
{
var serviceProvider = this.GetService<IServiceProvider>();
var items = new Dictionary<object, object>();
var entities = from entry in ChangeTracker.Entries()
where entry.State == EntityState.Added || entry.State == EntityState.Modified
select entry.Entity;
foreach (var entity in entities)
{
var context = new ValidationContext(entity, serviceProvider, items);
var results = new List<ValidationResult>();
if (Validator.TryValidateObject(entity, context, results, true)) continue;
foreach (var result in results)
{
if (result == ValidationResult.Success) continue;
var errorMessage = $"{entity.GetType().Name}: {result.ErrorMessage}";
throw new ValidationException(errorMessage);
}
}
}
Note that it's not necessary to override the other SaveChanges overloads, because they call these two.
The Error tells you that youre writing more characters to a field than it can hold.
This error for example would be thrown when you create a given field as NVARCHAR(4) or CHAR(4) and write 'hello' to it.
So you could simply check the length of the values you read in to find the one which is causing your problem. There is at least on which is too long for a field.

Casting issue while returning value in method in EF4.0

I'm trying to load employees using Entity Framework.
The method is supposed to return employee list.
It' s giving this error:
Cannot implicit convert....<Class names and methods>.... An Explicit conversion exists.
I think the problem is related to casting.
Please check below code.
public List<Employee> LoadEmployees()
{
try
{
EMployeeDB1Entities EE = new EMployeeDB1Entities();
var Employees = EE.Employees.Where(p => p.Name.StartsWith("T"));
return Employees;
}
catch
{
return null;
}
}
var Employees = EE.Employees.Where(p => p.Name.StartsWith("T")).ToList();
Update your code to:
return Employees.ToList();
Also do note that this is the ToList() method that actually triggers the database query.
EE.Employees.Where(....) doesn't query the database. The DB is queried when the result of the Where() is enumerated, which is what .ToList() does.
Thanks it works...one more issue, suppose if I want to bind above list
to grid then how can I bind ?
Assuming you're using WPF or Silverlight:
To bind the result of your query on a datagrid, you could expose a public property of type ObservableCollection.
This collection accepts an IEnumerable<T> object as constructor.
You can write:
var myCollection = new ObservableCollection<Employee>(this.LoadEmployees());
Then bind the ItemSource property of your datagrid to your collection.
If you have more problems using bindings, I recommend you to ask another question, because the subject is quite different.

How to replace an existing collection on an Entity Frameworks POCO object

Let's say I create a new Entity and Save it as follows:
UserReport report = new UserReport() {//set the props}
manager.SaveUserReport(report)
Public UserReport SaveUserReport(UserReport report)
{
using(var context = new ReportDatabase())
{
context.UserReports.AdObject(report);
context.SaveChanges();
}
return report;
}
so far so good
I then read back the saved Report
savedReport = manager.GetUserReports(new int[] {report.Id}).FirstOrDefault();
Public List<UserReport> GetUserReports(IEnumerable<int> reportIds)
{
using (var context = new ReportDatabase())
{
var reports = from UserReport in context.UserReports
where reportIds.Contains(userReport.Id)
select userReport;
return visibleReports.ToList();
}
}
savedReport is now an attached UserReport
The UserReport object has a collection of Columns attached to it.
I want to replace the set of Columns attached with another set (that already exist in the database).
savedReport.Columns = newColumnCollection
This fails with the error "The property Columns" on type UserReport_etc' cannot be set because the collection is already set to an EntityCollection"
I've looked at this article: the problem is the same, but I cannot use that solution.
What is the correct way to tackle this?
OK - looks like it's just a case of setting the non-navigation properties to not be virtual.
That is one hell of a weird situation, given that the behaviour that is modified is of properties that remain as virtual.

Execute StoredProcedure in CodeFirst 4.1

I understand stored procedures mapping is not supported by my understanding is that I should be able to call stored procedures.
I have quite a few complex stored procedures and with the designer I could create a complex type and I was all good.
Now in code first let's suppose I have the following stored procedure, just put together something silly to give an idea. I want to return a student with 1 address.
In code I have A Student and Address Entity. But no StudentAddressEntity as it's a link table.
I have tried the following but I get an error
Incorrect syntax near '."}
System.Data.Common.DbException {System.Data.SqlClient.SqlException}
ALTER Procedure [dbo].[GetStudentById]
#StudentID int
AS
SELECT *
FROM Student S
left join StudentAddress SA on S.Studentid = sa.studentid
left join Address A on SA.AddressID = A.AddressID
where S.StudentID = #StudentID
C# code:
using (var ctx = new SchoolContext())
{
var student = ctx.Database.SqlQuery<Student>("GetStudentById,#StudentID",
new SqlParameter("StudentID", id));
}
Any examples out there how to call sp and fill a complexType in code first, using out parameters etc.. Can I hook into ADO.NET?
Trying just an SP that returns all students with no parameters I get this error
System.SystemException = Cannot create a value for property
'StudentAddress' of type
'CodeFirstPrototype.Dal.Address'. Only
properties with primitive types are
supported.
Is it because I have in a way ignore the link table?
Any suggestions?
I believe that your exception actually is:
Incorrect syntax near ','.
because this is invalid statement: "GetStudentById,#StudentID". It should be without comma: "GetStudentById #StudentID".
The problem with stored procedures in EF is that they don't support loading navigation properties. EF will materialize only the main entity and navigation properties will not be loaded. This is solved for example by EFExtensions. EFExtensions are for ObjectContext API so you will have to check if it is also usable for DbContext API.
Using EFExtentions it will look something like
using (var context = new SchoolContext())
{
var command = context.CreateStoreCommand("GetStudentById", CommandType.StoredProcedure,
new SqlParameter("StudentID", id));
using (command.Connection.CreateConnectionScope())
using (var reader = command.ExecuteReader())
{
// use the reader to read the data
// my recommendation is to create a Materializer using EFExtensions see
// http://blogs.msdn.com/b/meek/archive/2008/03/26/ado-entity-framework-stored-procedure-customization.aspx
// ex
var student = Student.Materializer.Materialize(reader).SingleOrDefault();
return student;
}
}

Accessing foreign key value (int) in Entity Framework

I just spent the last 3-4 hours trying to retrieve a foreign key value using linq to entities and a stored procedure. Any advice is much appreciated.
public JsonResult GetEvents(double? start, double? end)
{
AnoEntities _dbAno = new AnoEntities();
var events = _dbAno.Events_GetByDateRange(fromDate, toDate);
var eventList = from e in events
select new
{
id = e.id,
title = e.title,
className = e.event_types.type.ToString()
};
return Json(eventList.ToArray());
}
type_id is the foreign key value that i'm trying to reach. I can't get it so appear in the entity data model and I can't seem to get to it. e.event_types and e.event_typesReference are both null so things like e.event_typesReference.EntityKey.EntityKeyValues.First().Value.ToString() aren't working.
Thanks!
I don't see any .Include methods or Load methods on even_types and I'm assuming your returning IEnumerable from your _dbAno.Events_GetByDateRange(fromDate, toDate). Like Craig pointed out in the comments if your return type of GetByDateRange is IQueryable you'd be projecting and EF should eager load for you.
Just a reminder that implicit lazy loading isn't supported out of the box in Entity Framework 1.0. You'll need to manually load the event_types with Load() or use the Include method on ObjectQuery.