I have such code using EntityFramework Alpha3 (from nuget):
class Member
{
[Key]
public int Key { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string Sitename { get; set; }
public DateTime? RegDate { get; set; }
}
class MembersContext : DbContext
{
public MembersContext()
: base("Name=ConnectionString")
{
}
public DbSet<Member> Members { get; set; }
}
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
Database.SetInitializer<MembersContext>(null);
const int memberKey = 1001;
using (var db = new MembersContext())
{
var query = from m in db.Members
where
m.Key == memberKey
&& EntityFunctions.DiffDays(m.RegDate, DateTime.Now) > 0
select m;
var member = query.FirstOrDefault();
}
return View();
}
}
I have tried to use EntityFunctions in fresh ASP.NET MVC project (based on .net 4.5) - it always fails with error:
LINQ to Entities does not recognize the method 'System.Nullable`1[System.Int32] DiffDays(System.Nullable`1[System.DateTime], System.Nullable`1[System.DateTime])' method, and this method cannot be translated into a store expression.
Same code works completely fine in Console app. Any ideas, what's wrong?
I suspect that in the case of your ASP.NET app, you also have a reference to System.Data.Entity, and that you are using the EntityFunctions class defined System.Data.Entity.
However, Entity Framework 6 has removed the dependency on System.Data.Entity and has redefined all necessary classes for that purpose inside of the EntityFramework assembly.
Meaning that, in the case of your console app, I am guessing that either by design (System.Data.Entity is not referenced) or by accident (System.Data.Entity is referenced but the EntityFunctions class is taken from EntityFramework.dll), the correct version of EntityFunctions (from EntityFramework.dll) is taken.
If you are using any version of Entity Framework 6, make sure that you are using the EntityFunctions class that can be found in EntityFramework.dll, not the one in System.Data.Entity. Source code of EntityFunctions.cs in Entity Framework 6
Actually, if you use Entity Framework 6, I would recommend removing all and any references to System.Data.Entity - in order to avoid any future confusion and mistake.
The reason why you're getting this error is that by design Linq to Entities converts all expression to server query. So it does not know how to translate DiffDays to SQL. Try to omit this method and rewrite expression.
UPDATE:
EntityFunctions are Canonical functions so you can use them in Linq to Entities. So the only reasonable explanation is in EF Alhpa version.
Resolved this by changing all my EntityFunctions.TruncateTime to DbFunctions.TruncateTime and the error went away after examining various using statements and removing all of those that referenced System.Data.
Related
Supposedly, I have a simple DbContext with Blog and Post models:
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
Let's say I have a stored procedure that returns some DTO:
[Keyless]
public class BlogPostDto
{
public string PostTitle { get; init; }
public string BlogName { get; init; }
}
Today I put the following into DbContext:
public class AppDbContext : DbContext {
public virtual DbSet<BlogPostDto> NeverUseIt { get; set; }
partial void OnModelCreatingPartial(ModelBuilder modelBuilder) {
modelBuilder.Entity<BlogPostDto>().ToView(null);
}
}
And then I can get Stored Procedure results shaped in the way I want:
List<BlogPostDto> results = await db.Set<BlogPostDto>().FromSqlRaw($"EXEC MyProc").ToListAsync();
So, my question is, do I have to add my BlogPostDto into DbContext? I know that in EF Core 3 I did; but there were a large number of improvements since then. Creating a bogus DbSet and mapping it to non-existent view just feels counter-intuitive!
The closest I found in most current documentation is here. The very first example of context is Serving as the return type for raw SQL queries. - but the article assumes that I have a matching view already in the database.
UPDATE: It looks like ToView(null) is not necessary - just DbSet<>
Nothing has changed in that regard so far from what you see in the EF Core 6.0 documentation and SO posts you are referring to.
Just to be crystal clear, you don't need a DbSet<T> returning property in your context. But you do need to include the type (keyless or not) in the model using the modelBuilder.Entity<T>() call, and also ToView(null) to prevent EF Core migrations associate database table and/or view with it, and optionally HasNoKey() in case you don;t want to use EF Core dependent attributes like [Keyless] in your data classes.
So the minimum requirement for your example is this line
modelBuilder.Entity<BlogPostDto>().ToView(null);
Now, this is a long time requested feature (which exists in the "obsolete" EF6 which the "modern" EF Core is supposed to replace), tracked by Support raw SQL queries without defining an entity type for the result #10753 issue in EF Core issue tracker. It was initially planned to be included in the upcoming EF Core 7.0 release (Nov 2022), but later has been cut for (eventually) EF Core 8.0 (Nov 2023). So until then you have to use the "register model" approach, or use 3rd party library(!) like Dapper for the same task, as suggested by one of the EF Core team members(?!).
I am creating an OData endpoint using the NuGet Microsoft.AspNetCore.OData within my ASP.Net Core website.
I had the idea to not make my database models public and map them using the LINQ Select function, to have more control about which properties are able to be shown to the outside, such as who created what.
In the future some more logic will be added to the IEnumerable because of permissions granted on the data.
Everything is working fine; I am able to get, filter and expand data on my ODataController. Except for one thing I noticed using the debugging options for Entity Framework Core; everything I send to my ODataController is being done in memory and not via an expression to Entity Framework as I expected. It requests everything each time. Of course, as the grows, this will become more and more a problem over time.
Some code resembling what I am doing
public class ExampleModel {
public Guid Id { get; set; }
public string Name { get; set; }
}
public class ExampleDbModel{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class ExampleRepository {
public IEnumerable<ContentItem> Get(string userId)
{
return this._dbContext.Example
.Select(ExampleMapper.Map) // Mapper is pure property to property in this example, same names
.Where(e => e.UserID == userId); // Permissions will be more complex
}
}
public class ExampleController : ODataController
{
// Constructor, properties, DI, ...
[EnableQuery]
public IActionResult Get()
{
return Ok(_exampleRepository.Get(SomeStaticVariableForUserId));
}
}
When calling the controller I always notice following query being done by Entity Framework Core
SELECT [ExampleDbModel].[Id], [ExampleDbModel].[Name]
FROM ExampleDbModel
Even when I am doing localhost:5050/odata/examplemodel?$select=id, it still performs the same query loading everything.
I am wondering what I am able to do to translate my OData queries straight to Entity Framework Core, to load as less as possible.
There seems to be something strange happening with regards to adding an entity set to an existing project vs having an entity set in its own project for re-usability.
Scenario One
Project A is a class library and has an EF set added to it and connected to a database.
Within the default class in the class library project, this code is written and compiles fine.
public void test()
{
using (var context = new Accu_CRM_dbEntities())
{
var test = context.BillableParts.First(P => P.Id == "test");
}
}
Scenario Two
Project B is another project added to the same solution. A reference is made to project A so as to use the identities in project B. A using statement is placed in the code file that is going to be making dB calls with the EF set. The same code is written into project B; however, the compiler complains that 'DAL.Accu_CRM_dbEntities': type used in a using statement must be implicitly convertible to 'System.IDisposable'. Aside from this, all intellisense support is lost when dealing with the context.
If I type context.BillableParts. intellisense support ceases after the entity name. What exactly is the reason that project B cannot see that Accu_CM_dbEntities should be disposable the way it is in project A?
namespace DAL
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class Accu_CRM_dbEntities : DbContext
{
public Accu_CRM_dbEntities()
: base("name=Accu_CRM_dbEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<BillablePart> BillableParts { get; set; }
public virtual DbSet<BillableService> BillableServices { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Part> Parts { get; set; }
public virtual DbSet<PartsManufacturer> PartsManufacturers { get; set; }
public virtual DbSet<WorkOrder> WorkOrders { get; set; }
}
}
Perhaps some more information on the database would have been a bit more useful. I am using SQL server compact. I used nuget and installed EF for sql compact within my consuming project (consumer of EF project) and everything was fixed. I am not 100% sure what was the issue exactly but obviously I did not have the correct libraries referenced. I'll leave this up here for anyone else that might be getting this error
I am using the code first approach to create the schema and then populating the data in it with the help of Seed method
I am using Entity Framework Version 5.0,SQLEXPRESS2008 and MVC4
below is my Model
public enum Grade
{
A, B, C, D, F
}
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
[DisplayFormat(NullDisplayText = "No grade")]
public Grade? Grade { get; set; }
public virtual Course Course { get; set; }
public virtual Student Student { get; set; }
}
this is how i populate the data to the Database using seed method in Intializer
var enrollments = new List<Enrollment>
{
new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
new Enrollment{StudentID=3,CourseID=1050},
new Enrollment{StudentID=4,CourseID=1050,},
new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
new Enrollment{StudentID=6,CourseID=1045},
new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
};
enrollments.ForEach(s => context.Enrollments.Add(s));
context.SaveChanges();
on debug ,I am able to see the data in "Grade" Column within that context
but it neither creates the Column "Grade" in Database nor populates its data.
I have setup the Context and Database Initalizer as below in my web.config
<entityFramework>
<context type="EntityFrameworkWithMVC.DAL.SchoolContext, EntityFrameworkWithMVC">
<databaseInitializer type="EntityFrameworkWithMVC.DAL.SchoolInitializer, EntityFrameworkWithMVC" />
</context>
</contexts>
</entityFramework>
You will need .NET 4.5
Enum support is not available in EF 5 with .NET 4.0. This is due to a change in System.Data.Entity which is located not in the EF 5 library but in the .NET 4.5 version.
See:
http://social.msdn.microsoft.com/Forums/en-US/55dc58a4-6190-4bad-b317-1787cf86bf3d/ef-5-but-no-enum-support?forum=adodotnetentityframework
Are there technical reasons EF 5 isn't fully supported on .NET4.0?
You'll need a workaround to extract your enum value (you can use int and convert to enum in your mappings) or upgrade to .NET 4.5
[UPDATE]
As for a workaround, there are a couple of options,
In all cases you'll need to write your enum value as a string or int (or other supported type) to the database:
Use a mapper
If you are using a ViewModel or something similar you can implement a configurable mapper like AutoFac (http://www.nuget.org/packages/Autofac/). It's a bit hard to use at first but it has all the features for IOC, MVC etc. You can define a custom mapping definition so that you can use the enum in your ViewModel and the int value in your entity. The custom mapping contains the conversion from int to enum and back.
Use a [NotMapped] column
This is faster to implement, but it usually bites you in the tail:
public int? GradeValue {get;set;}
[NotMapped]
[DisplayFormat(NullDisplayText = "No grade")]
public Grade? Grade
{
get
{
return GradeValue.HasValue ? (Grade?) GradeValue.Value : null;
}
}
The [NotMapped] attribute ensures the enum is not added to the database (might come in handy if you'll decide to upgrade to .NET 4.5 later on).
Now you can read the value as an enum. My guess is that GradeValue needs to be public (private/protected would give you some advantages) (not sure if supported in this version). If it has to be public; its kind of tricky because other developers might use this GradeValue directly.
Alternatively you can do something similar for the set instruction.
Hope this helps.
Just as mentioned in this post, I am getting a Json serialization error while serializing an Entity Framework Proxy:
A circular reference was detected while serializing an object of type
'System.Data.Entity.DynamicProxies.PurchaseOrder_446B939192F161CDBC740067F174F7A6059B0F9C0EEE68CD3EBBD63CF9AF5BD0'.
But the difference is, I don't have a circular reference in my entities, and it only occurs in our production environment. Locally everything works fine...
My Entities:
public interface IEntity
{
Guid UniqueId { get; }
int Id { get; }
}
public class Entity : IEntity
{
public int Id { get; set; }
public Guid UniqueId { get; set; }
}
public class PurchaseOrder : Entity
{
public string Username { get; set; }
public string Company { get; set; }
public string SupplierId { get; set; }
public string SupplierName { get; set; }
public virtual ICollection<PurchaseOrderLine> Lines { get; set; }
}
public class PurchaseOrderLine : Entity
{
public string Code { get; set; }
public string Name { get; set; }
public decimal Quantity { get; set; }
}
The GetCurrent action on my PurchaseOrderController throwing the exception:
public class PurchaseOrderController : Controller
{
private readonly IUnitOfWork _unitOfWork;
public PurchaseOrderController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public JsonResult GetCurrent()
{
return Json(EnsurePurchaseOrder(), JsonRequestBehavior.AllowGet);
}
private PurchaseOrder EnsurePurchaseOrder()
{
var company = RouteData.GetRequiredString("company");
var repository = _unitOfWork.GetRepository<PurchaseOrder>();
var purchaseOrder = repository
.Include(p => p.Lines)
.FirstOrDefault
(
p => p.Company == company &&
p.Username == User.Identity.Name
);
if (purchaseOrder == null)
{
purchaseOrder = repository.Create();
purchaseOrder.UniqueId = Guid.NewGuid();
purchaseOrder.Company = company;
purchaseOrder.Username = User.Identity.Name;
_unitOfWork.SaveChanges();
}
return purchaseOrder;
}
}
Option 1 (recommended)
Try turning off Proxy object creation on your DbContext.
DbContext.Configuration.ProxyCreationEnabled = false;
Typically this scenario is because the application is using POCO objects (Either T4 Generated or Code-First). The problem arises when Entity Framework wants to track changes in your object which is not built into POCO objects. To resolve this, EF creates proxy objects which lack the attributes in the POCO objects, and aren't serializable.
The reasons why I recommend this approach; using a website means that you probably don't need change tracking (stateful) on Entity Framework objects, it free's up memory and cpu because change tracking is disabled and it will work consistantly on all your objects the same way.
Option 2
Use a serializer (like JSON.Net which is already included in ASP.Net 4) that allows customization to serialize the object(s).
The reasons I do not recommend this approach is that eventually custom object serialization logic will be need to serial proxy objects as other objects types. This means you have a dependency on logic to deliver a result downstream. Changing the object means changing logic, and in an ASP.Net MVC project (any version) instead of only changing a View you have some thing else to change that is not readily known outside of whoever wrote the logic first.
Option 3 (Entity Framework 5.x +)
Use .AsNoTracking() which will disable the proxy objects on the specific query. If you need to use change tracking, this allows a nice intermediate solution to solution #1.
Your POCO entities are perfectly serializable. Your problem is that the dynamic proxies the EF runtime creates for you are usually not. You can set the context.Configuration.ProxyCreationEnabled to false but then you lose lazy loading. My strong recommendation to you is to use Json.NET which supports serialization for EF entities:
ADO.NET Entity Framework support accidently added to Json.NET
Popular high-performance JSON framework for .NET
I spent countless hours attempting all of the various solutions I found scattered throughout the web, including:
[JsonIgnore]
Internal Getters
Disabling LazyLoadingEnabled and ProxyCreationEnabled
Setting ReferenceLoopHandling to "ignore"
Carefully using explicit loading where needed
All of which ultimately proved fruitless for me. Ignoring a property helped one query, but hurt 3 others. It felt like the programming equivalent to whack-a-mole.
The context of my problem was that the data going in an out of my application had to be JSON. No way around it. Inserts and updates obviously pose much less of a problem. But selecting data that's stored in a normalized database (and in my case including a version history) to be serialized is a nightmare.
The solution:
Return the data (properties) you need as anonymous objects.
A code example:
In this case I needed the 3 latest tickets, based on "Date Scheduled". But also needed several properties stored in related entities.
var tickets =
context.TicketDetails
.Where(t => t.DateScheduled >= DateTime.Now)
.OrderBy(t => t.DateScheduled)
.Take(3)
.Include(t => t.Ticket)
.Include(t => t.Ticket.Feature)
.Include(t => t.Ticket.Feature.Property)
.AsEnumerable()
.Select(
t =>
new {
ID = t.Ticket.ID,
Address = t.Ticket.Feature.Property.Address,
Subject = t.Ticket.Subject,
DateScheduled = String.Format("{0:MMMM dd, yyyy}", t.DateScheduled)
}
);
And voila, no self referencing loops.
I realize this situation may not be adequate in all cases given that entities and objects may change. But it's certainly worth some consideration if all else fails.
Whatever classes have the reference of other class just add attribute like this
[Newtonsoft.Json.JsonIgnoreAttribute]
public virtual ICollection<PurchaseOrderLine> Lines { get; set; }
Now everything work smooth
I was having the same issue, what I have done is have passed only needed column to view , In my case. only 2.
List<SubCategory> lstSubCategory = GetSubCateroy() // list from repo
var subCategoryToReturn = lstSubCategory.Select(S => new { Id = S.Id, Name = S.Name });
return this.Json(subCategoryToReturn , JsonRequestBehavior.AllowGet);
I had the same error, however I saw it both on production server and locally. Changing the DbContext configuration didn't quite solve my issue. A different solution was presented to me with the
[IgnoreDataMember]
attribute on DB entity references. See the post here if this sounds more pertinent to your issue.
ASP.NET Web API Serialized JSON Error: "Self Referencing loop"
In your DbContext class, add this line of code:
this.Configuration.ProxyCreationEnabled = false;
For example:
public partial class EmpDBEntities : DbContext
{
public EmpDBEntities()
: base("name=EmpDBEntities")
{
this.Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Department> Departments { get; set; }
public virtual DbSet<Employee> Employees { get; set; }
}
The circular reference happens because you use eager loading on the object.
You have 3 methods:
Turn off eager loading when your loading your Query (linq or lambda)
DbContext.Configuration.ProxyCreationEnabled = false;
Detach the objects (= no eager loading functionality & no proxy)
Repository.Detach(entityObject)
DbContext.Entry(entityObject).EntityState = EntityState.Detached
Clone the properties
You could use something like AutoMapper to clone the object, don't use the ICloneable interface, because it also clones the ProxyProperties in the object, so that won't work.
In case you are building an API, try using a separte project with a different configuration (that doesn't return proxies)
PS. Proxies is the object that's created by EF when you load it from the Entity Framework. In short: It means that it holds the original values and updated values so they can be updated later. It handles other things to ;-)
I had the same problem and resolved it by un-checking Json.NET in the project Extensions in the Reference Manager.
(see the image http://i.stack.imgur.com/RqbXZ.png)
I also had to change the project.csproj file to map the correct path for the new version:
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.6.0.5\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
and still had to configure the web.config
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
Note that in the web.config file I was forced to refer to the OLDER (6.0.0.0) version though the installed version was 6.0.5.
Hope it helps!