I have a weird error I cannot understand. After setting breakpoints and local watches it came to this:
How can _temp be true (i.e., the collection db.Users contains a user of name "dummy") although the collection db.Users is empty?
For completeness:
public class DBCUsers : DbContext {
public DbSet<User> Users { get; set; }
}
public class User {
public int ID {get; set;}
public string Name {get; set;}
}
DbSet<T>.Local contains a collection of entries already retrieved from the database by previous queries. Among other things, the idea is to save unnecessary round trips.
Unless you have previously executed queries in the context to retrieve User entities, Local will be empty. Your call to Any() can be translated into a SQL query which returns a boolean, so it does not cause the context to retrieve any entities.
To resolve your problem, either use the straightforward db.Users.Count(), which will query the database to get the count, or populate Local with a call to Load(), which as of EF6 is available in QueryableExtensions in System.Data.Entity.
Related
Using Entity Framework 6.0, I am attempting to implement table splitting to improve query performance on tables with columns that contain BLOB data. I have followed the recommendations in this tutorial and it does indeed work as described.
Here's a very simplified example of the entity classes that map to one of my split tables ...
public class MyEntity
{
public string Id { get; set; }
public virtual MyEntityContent Content { get; set; }
public string Name { get; set; }
}
public class MyEntityContent
{
public string Id { get; set; }
public virtual MyEntity Entity { get; set; }
public byte[] Blob { get; set; }
}
... and the corresponding configuration code in the associated DbContext implementation ...
modelBuilder.Entity<MyEntity>().HasKey(e => e.Id).ToTable("MyEntities");
modelBuilder.Entity<MyEntityContent>().HasKey(c => c.Id).ToTable("MyEntities");
modelBuilder.Entity<MyEntity>().HasRequired(e => e.Content).WithRequiredPrincipal(d => d.Entity);
Given that the lazy-loaded Content property is Required by Entity Framework, it seems sensible to initialize it to a default value in the constructor of the containing MyEntity class ...
public MyEntity()
{
Content = new MyEntityContent();
}
... which enables a new instance of the class to be created and partially populated, without the risk of an exception being thrown by forgetting to initialize the required property value:
var entity = new MyEntity {Id = "XXX", Name = "something"};
I typically use a similar technique to initialize collection properties on EF entities and it works fine. However, in the above scenario, this initialization in the constructor has an unexpected effect: when retrieving existing entity instances from the database, the database value in the lazy-loaded property is ignored in favor of the empty default value.
This seems illogical to me. Doesn't Entity Framework create an entity object by first calling its default constructor and then applying its own property values to the created instance? If so, this should overwrite my default Content property value with a new instance of MyEntityContent, based on database data. This is how it seems to work with lazy-loaded collection properties.
If it's not possible to do this in the way I am expecting, is there an alternative technique for initializing lazy-loaded properties?
Don't initialize virtual members and perhaps, if you have to, handle any exceptions from uninitialized members.
I just had this issue with an entity with two virtual fields. Originally I had it initialize those two, but after removing them (and initializing the other fields to some default value), it started working for me. Try it out and let me know!
[Edit] I just realized I replied this to a slightly old post, didn't see the date. I guess I'll leave this answer here in case.
I am using Entity Framework/Fluent API and I am new to them. In my scenario I am having the following three classes.
public class Review
{
public int Id { get; private set; }
public float AverageRating { get; private set; } //Computed Field
public int TotalLikes { get; private set; } //Computed Field
public List<Rating> Ratings { get; private set;}
public List<Like> Likes { get; private set;}
}
public class Rating
{
public int CustomerId { get; private set; }
public int ReviewId { get; private set; }
public int Rating { get; set; }
}
public class Like
{
public int CustomerId { get; private set; }
public int ReviewId { get; private set; }
}
I have Fluent mapping for all three classes and their relationships. In the review class I have two computed fields. I could populate computed fields from child collections (Ratings and Likes). In that case in the Linq query I have to include both child collections, which I believe is a performance intensive operation. Alternatively I could also use computed columns in the DB. But I don't like to put anything in the database side. So, what is the best way of populating the computed fields (mostly aggregate operations like Count, Average, etc) without loading the child collections or using a database solution?
If you don't want to use a database solution like a stored procedure or using computed columns on the database side then this leaves us with one option i guess. That is have a method in your repository like GetRatings() or something similar and use a linq query in that method to compute ratings, of course LINQ to Entities will convert that Linq query to a native SQL query which should be faster as it is native to the database.
With out using Database solution...
Linq has count/max/average,Sum,groupby,distinct .... etc So Pulling data back once the DB has "calculated it", such as a count or sum integer isnt normally an issue.
So no need to drag back all objects.
The use of concurrency checking to keep integrity when posting back . ie Timestamp EF type Rowversion, Will be necessary
Basically with EF you put a value in the context and SAY Save.
So the key thing to remember is when Saving, how to make sure the data is OK.
Thats the role of the Rowversion. (optimistic locking)
If the record you are changing has changed since you read it, fail.
You re-read/recalc and try again.
However, if your application demands pessimistic locking
then this article from Ladislav is recommended reading
Essentially EF doesnt offer Pessimistic locking.
HOWEVER, you can call the DB using methods exposed on EF, or just call the DB.
Context.Database.ExecuteSqlCommand()
Note by default EF does not read Dirty data.(ie no uncommitted read)
After all that you still need/want pessimistic locking semaphore style to access to the data.
then see Application Lock on SQL server
YEP you will need the DB, unless you have an ENQUEUE server handy;-)
Consider the below Order object as an Entity Framework entity.
If I was to cast an instance of Order down to IOrder, and then access the Lines property on IOrder, would that cause the virtual OrderLines property to enumerate and load all the OrderLine entities from the database, returning a populated collection of OrderLine entities in memory?
Or will the client code just get a reference to the OrderLines collection, which will load the entities from the database once it is actually enumerated such as in a foreach?
public interface IOrder
{
IEnumerable<OrderLine> Lines { get; }
}
public class Order : IOrder
{
public int OrderId { get; set; }
public IEnumerable<OrderLine> Lines
{
get
{
return OrderLines;
}
}
public virtual ICollection<OrderLine> OrderLines { get; set; }
public Order()
{
OrderLines = new List<OrderLine>();
}
}
It will return a reference to the OrderLines object, but exposed as IEnumerable. Which means that only an enumeration in client code will actually enumerate the the collection. This is the entire collection: linq filters (Where) and projections (Select) will not be translated to SQL.
Note that this neither of these may be desired. First, the context must be alive to allow lazy loading and second, the collection may be 'large' (although with order lines that probably won't be a point). Depending on the type of application it may be better to transfer a pre-populated OrderDto object to the client.
Say I have Project and Task EF Code first classes
public class Project
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
}
public class Task
{
public int ID { get; set; }
public string Name { get; set; }
public int ProjectId { get; set; }
public bool IsDeleted {get; set;}
public virtual Project Project { get; set; }
}
Say I have
public void SomeAction()
{
Project p= repository.GetById(1);
var tasks = p.Tasks;
//var tasks = p.Tasks.Where(t=>t.IsDeleted==false);
}
I would like that my Tasks property on the Project class will always perform that filter on IsDeleted and just return that subset ... to avoid having to write that condition all over the place...
Any recommendations?
Edit:
Im using EF Code First
Add a discriminator to your model in the OnModelCreating method
modelBuilder.Entity<TEntity>().Map(m => m.Requires("IsDeleted").HasValue(false));
Caveats
You can no longer load deleted items (unless you map IsDeleted true to another entity, then you may lose your automatic filtering)
The poco class cannot have the IsDeleted property (discriminators cannot be mapped)
because the IsDeleted cannot be mapped you need to run raw SQL to delete the entity in the first place.
EF Code first = NO WAY. Just one from long list of features which is available in EDMX and it is completely missing in code first. Mapped condition from EDMX does this but it is still problematic because it is hardcoded and cannot be changed (= you will never be able to load deleted entities even if you want to unless you use another EDMX). The solution would be implementation of global filters in EF but EF doesn't have anything like that despite the fact that old Linq-to-entities have them at least for relations (DataLoadOptions.AssociateWith).
This is much more painful in relations where you cannot use eager or lazy loading without loading deleted entities to your application as well and do filtering in your application's memory.
In the Model Designer, select your Task entity, and bring up the Mapping Details window. This should show you the database table your entity is mapped to, and all the columns. Just under where it says "Maps to [YourTable]" you should see an option <Add a Condition>. This should let you set a condition like what you're looking for.
I'm trying to update multiple records using entity framework, but am not sure how to proceed.
Basic setup:
class Appointment
{
public int Id {get; set;}
public double Charge {get; set;}
public DateTime Time {get; set;}
}
The view presents a list of appointments, and then the call to controller Post action passes in an Ienumerable<Appointment>.
public async Task<int> UpdateAppointments(IEnumerable<Appointment> appointments){
// code goes here
var appointmentsToUpdate = await _context
.Appointments
.Where(a => a.time > DateTime.Now).ToListAsync();
// what to do here??
// loop through appointmentsToUpdate and find the relevant
// record inside appointment, and then do an update?
// Seems like a merge would be more efficient.
}
What i want to do is merge appointments and appointmentsToUpdate and update the appointment time. In another scenario, with a different authorization, I want the administrator, for example, to only be able to change the appointment charge, so deleting all records and appending the new records isn't an option.
It seems like you can do this with pure sql statements, but then the appointments parameter is passed in as an IEnumerable, not as a table already in the database as in this answer: Bulk Record Update with SQL
First of all, can you do this kind of update using Linq? Does it translate directly to entity framework (core)?
Without extension projects or store SQL the best you can do is to attach the Appointments as unchanged entities, and mark the target property as modified.
The Appointments you attach just need the Key Properties and the Time populated.
Like this:
class Db : DbContext
{
public DbSet<Appointment> Appointments { get; set; }
public void UpdateAppointmentTimes(IEnumerable<Appointment> appointments)
{
foreach(var a in appointments)
{
this.Appointments.Attach(a);
this.Entry(a).Property(p => p.Time).IsModified = true;
}
this.SaveChanges();
}
. . .
Which will update only the changed column for all those appointments in a single transaction.