I've got POCO domain entities that are persisted using Entity Framework 5. They are obtained from the DbContext using a repository pattern and are exposed to a RESTful MVC WebApi application through a UoW pattern. The POCO entities are proxies and are lazy loaded.
I am converting my entities to DTOs before sending them to the client. I am using Automapper to do this and it seems to be working fine with Automapper mapping the proxy POCOs to DTOs, keeping the navigation properties intact. I am using the following mapping for this:
Mapper.CreateMap<Client, ClientDto>();
Example of Domain/DTO objects:
[Serializable]
public class Client : IEntity
{
public int Id { get; set; }
[Required, MaxLength(100)]
public virtual string Name { get; set; }
public virtual ICollection<ClientLocation> ClientLocations { get; set; }
public virtual ICollection<ComplianceRequirement> DefaultComplianceRequirements { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
public class ClientDto : DtoBase
{
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
public ICollection<ClientLocation> ClientLocations { get; set; }
public ICollection<ComplianceRequirementDto> DefaultComplianceRequirements { get; set; }
public ICollection<Note> Notes { get; set; }
}
Now I am trying to update my context using DTOs sent back up from the wire. I am having specific trouble with getting the navigational properties/related entities working properly. The mapping for this I'm using is:
Mapper.CreateMap<ClientDto, Client>()
.ConstructUsing((Func<ClientDto, Client>)(c => clientUow.Get(c.Id)));
Above, clientUow.Get() refers to DbContext.Set.Find() so that I am getting the tracked proxy POCO object from EF (that contains all of the related entities also as proxies).
In my controller method I am doing the following:
var client = Mapper.Map<ClientDto, Client>(clientDto);
uow.Update(client);
client successfully is mapped, as a proxy POCO object, however it's related entities/navigational properties are replaced with a new (non-proxy) POCO entity with property values copied from the DTO.
Above, uow.Update() basically refers to a function that performs the persist logic which I have as:
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
_context.SaveChanges();
The above doesn't persist even persist the entity, let alone related ones. I've tried variations on the mappings and different ways to persist using detaching/states but always get "an object with the same key already exists in the ObjectStateManager" exceptions.
I've had a look at countless other threads and just can't get it all working with Automapper. I can grab a proxy object from the context and manually go through properties updating them from the DTO fine, however I am using Automapper to map domain -> DTO and it would be alot more elegant to use it to do the reverse, since my DTOs resemble my domain objects to a large extent.
Is there a textbook way to handle Automapper with EF, with Domain Objects/DTOs that have navigational properties that also need to be updated at the same time?
UPDATE:
var originalEntity = _entities.Find(entity.Id);
_context.Entry<T>(originalEntity).State = System.Data.EntityState.Detached;
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
The above persistence logic updates the 'root' EF proxy object in the context, however any related entities are not updated. I'm guessing that this is due to them not being mapped to EF proxy objects but rather plain domain objects. Help would be most appreciated!
UPDATE:
It seems that what I'm trying to achieve is not actually possible using the current version of EF(5) and that this is a core limitation of EF and not to do with Automapper:
Link
Link
I guess it's back to doing it manually. Hope this helps someone else who is wondering the same.
You have allready identified the problem:
The above persistence logic updates the 'root' EF proxy object in the
context, however any related entities are not updated
You are setting the modified state on the root node only. You must write code to iterate through all the objects and set the state to modified.
I implemented a pattern to handle this hierarchy model state with EF.
Every entity model class implements an interface like below, as do the view model classes:
public interface IObjectWithState
{
ObjectState ObjectState { get; set; }
}
The ObjectState enumeration is defined below:
public enum ObjectState
{
Unchanged = 0,
Added = 1,
Modified = 2,
Deleted = 3
}
For example when saving a deep hierarchy of objects using EF, I map the view model objects to their equivalent entity objects, including the ObjectState.
I then attach the root entity object to the context (and consequently all child objects):
dbContext.MyCustomEntities.Attach(rootEntityObj);
I then have an extension method on the DbContext that loops through all the items in the context's change tracker and update each entity's state (as you have done above).
public static int ApplyStateChanges(this DbContext context)
{
int count = 0;
foreach (var entry in context.ChangeTracker.Entries<IObjectWithState>())
{
IObjectWithState stateInfo = entry.Entity;
entry.State = ConvertState(stateInfo.ObjectState);
if (stateInfo.ObjectState != ObjectState.Unchanged)
count++;
}
return count;
}
Then we can simply save the changes as normal:
dbContext.SaveChanges();
This way, all the hierarchy of child objects will be updated accordingly in the database.
What you want to do is get the Entity from the database first:
var centity = _context.Client.First(a=>a.Id = id)
Then you map over this and update (this is what you were looking for, it will only map things it finds in the inputDTO, and leave the other properties alone)
Mapper.Map<UpdateClientInput, Client>(inputDto, centity);
_context.update();
Related
The entity/model has a child object, during ADD (POST) operations where I just want the parent object to be updated in the database, I simply set the child object to null. Parent object adds to database just fine and child object doesn't touch the database.
However, when I do an UPDATE (PUT) and set the same child object to null, the parent object is actually deleted from the database and child object not touched in the database?
Model code:
namespace PROJ.API.Models
{
public partial class Todo
{
public Todo()
{
}
public long TdoId { get; set; }
public string TdoDescription { get; set; } = null!;
public long PtyId { get; set; }
public virtual Priority? Priority { get; set; }
}
public partial class Priority
{
public Priority()
{
}
public long PtyId { get; set; }
public byte PtyLevel { get; set; }
public string PtyDescription { get; set; } = null!;
}
}
Entities code:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace PROJ.API.Entities
{
public class Todo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long TdoId { get; set; }
public string TdoDescription { get; set; } = null!;
public long PtyId { get; set; }
[ForeignKey("PtyId")]
public virtual Priority? Priority { get; set; }
}
public class Priority
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long PtyId { get; set; }
public byte PtyLevel { get; set; }
public string PtyDescription { get; set; } = null!;
}
}
Repository code:
public async Task<Todo?> GetTodoAsync(long tdoId)
{
var todo = await _context.Todo.Where(c => c.TdoId == tdoId)
.Include(x => x.Priority)
.FirstOrDefaultAsync();
return todo;
}
Controller code:
[HttpPut()] // UPDATE
public async Task<ActionResult> UpdateTodoAsync(Todo todo)
{
var eTodo = await _myRepository.GetTodoAsync(todo.TdoId);
if (todo.Priority == null || todo.Priority.PtyId == 0)
{
var priority = await _myRepository.GetPriorityAsync(todo.PtyId);
if (priority != null)
{
_mapper.Map(priority, todo.Priority);
}
}
_mapper.Map(todo, eTodo);
await _myRepository.SaveChangesAsync();
return NoContent();
}
My understanding is that setting the child object to null tells EF to NOT perform any operation on it in the database. TODO.PtyId is setup with a FK to PRIORITY.PtyId in the SQL database but I have NOT defined this in context (OnModelCreating) as I don't "think" I need the Fluent API approach here.
Any thoughts on what I'm doing wrong and/or why an UPDATE is actually deleting a record when I set a child object to NULL? As I noted before an ADD using the same null approach works just fine.
A couple things.
In your example and naming convention you should be explicitly nominating your FK either by attribute or fluent declaration. EF's convention is to base FK names on the "type" of the relationship, not the property name. So for instance if you have:
public virtual Priority? Pty { get; set; }
EF will be looking for a FK named Priority_ID or PriorityID, not PtyID. This behaviour may have changed in EF Core, I honestly haven't delved back into whether EF conventions can be trusted to work this out.
Lastly, this is overall a typical example of issues that can come up whenever you mix concerns with entities and use detached entities as view models. It's also outlining an issue with your repository implementation. In your case you are detaching an entity, then when passing it back to the server to update, loading the entity from data state, and using Automapper to copy the values across.
The first problem is that your repository is automatically and unconditionally eager-loading the related entity when in at least this example you don't need or want that related entity. When EF eager loads a relationship and then you set that related entity to #null, the proxy records this action and EF will interpret that as "Remove this relationship". If the related entity is not loaded/associated and left as #null when saving that top-level entity, nothing is removed. Either way you will want to avoid doing something like setting a related entity to #null if you don't want to save changes to them. The solution is either not to load related entities in the first place, ignore mapping across related entities, or marking those entities as Unchanged to avoid persisting changes to them.
Not loading Related entities:
This could either be solved by adding arguments to indicate what should be eager loaded, or considering adopting IQueryable for the repository method:
Argument:
public async Task<Todo?> GetTodoAsync(long tdoId, bool includeRelated = true)
{
var query = _context.Todo.Where(c => c.TdoId == tdoId);
if (includeRelated)
{
query = query.Include(c => c.Pty);
}
return query.FirstOrDefaultAsync();
}
In simple cases this isn't too bad, but in more complex entities it can be a pain, especially if you want to selectively include relatives. This way when you load eToDo from data state, you can tell it to not eager load the Priority. This isn't foolproof as it is still possible that a Priority could be associated if that DbContext instance had previously loaded the Priority associated with that Todo. Tracked entities will be associated even if you don't explicitly eager load them. To be safe this should be combined with the Automapper changes further below.(Excluding mapping changes) This is still a worthwhile change as you can avoid resource/performance costs of unconditionally eager loading every read.
IQueryable:
public IQueryable<Todo> GetTodoById(long tdoId)
{
var query = _context.Todo.Where(c => c.TdoId == tdoId);
return query;
}
IQueryable gives your consumer a lot more flexibility into what it wants to do with regards to data that will be coming back, but it does require a shift in thinking around the unit of work pattern to move the scope of the DbContext out into a Unit of Work so that consumers are responsible for that scope rather than at the individual repository level. The advantages of this approach are that the unit of work (DbContext scope) can be shared across repositories if needed, and with this pattern your consumer has control over things like:
Projection using Select or Count, Any, etc.
async vs. synchronous operations.
Assessing whether or not to eager load related entities.
So as an example with this pattern, the controller or service code would function more like:
[HttpPut()] // UPDATE
public async Task<ActionResult> UpdateTodoAsync(Todo todo)
{
using (var contextScope = _contextScopeFactory.Create())
{
var eTodo = await _myRepository.GetTodoById(todo.TdoId)
.SingleAsync();
_mapper.Map(todo, eTodo);
await contextScope.SaveChangesAsync();
return NoContent();
}
}
contextScope / _contextScopeFactory are a UoW pattern called DbContextScope by Medhi El Gueddari for EF6 which has a number of forks covering EF Core. I like this pattern as it gives the Repository a dependency to a locator to resolve the DbContext from the Scope rather than passing around DbContext instances, giving that scope full control over whether or not SaveChanges() gets committed or not. Leveraging IQueryable enables projection so it can help avoid this issue all-together when used to read data to send to a view to Project to a ViewModel using Automapper's ProjectTo rather than sending Entities to a View which come back to the controller as a deserialized and typically incomplete shell of what they once were.
Excluding mapping changes:
This involves adjusting the mapping you use to exclude copying across changes to the related entity when mapping one Todo across to another. If the mapping ignores Todo.Pty then you can map across just the Todo fields from the one instance to the DB instance and save the DbInstance without change tracking tripping anything changing in Pty or the relationship.
Marking as Unchanged:
Given your repository is managing the scope of the DbContext what you will likely need to do is add a method to isolate changes to just that top-level entity. Since the Repository is scoping the DbContext, this means some form of clunky method since we need to pass the entity to tweak tracking.
// eTodo.Pty = null; don't do
_myRepository.IgnoreRelatedChanges(eTodo);
await _myRepository.SaveChangesAsync();
then...
public void IgnoreRelatedChanges(Todo todo)
{
_context.Entry(todo.Pty).State = EntityState.Unchanged;
}
The trouble with this approach is that it is clumsy and prone to bugs/exceptions.
In any case that should provide you with some options to consider to solve your issue, and possibly consider for updating your repository pattern.
I am new to EF Core 6.0.1, using it with Blazor (WebAssembly), .NET 6.0, and Visual Studio 2022. I am creating a database of internal software projects, including their author(s) and maintainer(s).
I am having trouble getting EF Core to take in a List of Authors / List of Maintainers as part of creating a new SoftwareItem from a webform submission.
SoftwareItem in defined (in part) as follows:
public class SoftwareItem
{
[Key]
public int SoftwareId { get; set; }
public string Name { get; set; }
public string CurrentVersion { get; set; }
public string Status { get; set; }
public List<Author> Authors { get; set; }
public List<Maintainer> Maintainers { get; set;}
[other properties omitted]
}
An Author is defined as follows:
public class Author
{
[Key]
public int AuthorId { get; set; }
public int SoftwareItemId { get; set; }
public int ProgrammerId { get; set; }
public Programmer Programmer { get; set; }
}
Maintainer is identical, except for having a MaintainerId instead of an AuthorId.
Programmer is defined as:
public class Programmer
{
[Key]
public int ProgrammerId { get; set; }
public string ProgrammerName { get; set; }
}
EF Core created the tables for me based on a migration, and I have manually populated the Programmer table with the nine people who might be an Author and/or a Maintainer.
I have a webform where the user can create a new SoftwareItem, with pre-populated drop-downs for Authors and Maintainers that, after querying the database, contain the potential ProgrammerNames. The user can assign up to three Authors and up to three Maintainers before submitting the webform (via an Author1 dropdown, an Author2 dropdown etc.) Submitting the webform calls the InsertSoftware method, included below.
Note that I'm not a fan of the repetition between the Author logic and Maintainer logic, and the List should probably be a HashSet (in case the same author is set in Author1 and Author2) but those are issues for another day. The Author1 and similar variables are the int IDs set by the webform. I've previously verified they are being set to the appropriate values via a JavaScript alert. An ID of 0 means the value was never set (e.g. there is no second author).
The SoftwareItem here is instantiated as a new object on OnIntializedAsync and bound as the webform's model.
public async Task InsertSoftware()
{
List<int> authorIdsToAdd = new List<int>();
authorIdsToAdd.Add(Author1);
authorIdsToAdd.Add(Author2);
authorIdsToAdd.Add(Author3);
SoftwareItem.Authors = new List<Author>();
foreach (int author in authorIdsToAdd)
{
if (author != 0)
{
foreach (Programmer programmer in ProgrammerList)
{
if (programmer.ProgrammerId == author)
{
Author addedAuthor = new Author();
addedAuthor.Programmer = new Programmer();
addedAuthor.Programmer.ProgrammerId = author;
SoftwareItem.Authors.Add(addedAuthor);
}
}
}
}
[repeat code for the Maintainers]
await Http.PostAsJsonAsync("api/softwareitem", SoftwareItem);
Navigation.NavigateTo("software/fetchsoftware");
}
The SoftwareItem API is (in part) as follows:
[HttpPost]
public async Task<IActionResult> Create([FromBody] SoftwareItem softwareItem)
{
_context.Software.Add(softwareItem);
await _context.SaveChangesAsync();
return Ok(softwareItem);
}
My understanding from this Stack Overflow question is that if objects have been instantiated for a navigation property when the parent entity is added and saved to the database context, then EF Core will also add the new navigation property values to their appropriate tables. However, that isn't happening, and all I'm getting is a 500 error in the console.
What I'm expecting is that...
A new entry will be inserted into the SoftwareItem table
New entries will be inserted into the Author table, containing an auto-incremented AuthorId, the SoftwareItem's SoftwareItemId, and the ProgrammerId from the webform
New entries will be inserted into the Maintainer table, containing an auto-incremented MaintainerId, the SoftwareItem's SoftwareItemId, and the ProgrammerId from the webform.
Ok, it's a bit difficult to make out what your code is precisely doing but there are a few issues I see.
First, with entities you should always avoid ever reinitializing navigation property lists. During inserts it's "ok", but anywhere else it would lead to bugs/errors so it's better to simply not see it in the code. Pre-initialize your properties in the entity itself:
public class SoftwareItem
{
// ...
public virtual ICollection<Author> Authors { get; set; } = new List<Author>();
public virtual ICollection<Maintainer> Maintainers { get; set;} = new List<Maintainer>();
}
This ensures the collections are ready to go when you need them for a new entity.
Next, it can be helpful to structure your code to avoid things like module level variables. Your InsertSoftware() method references an instance of SoftwareItem and it isn't clear where, or what this reference would be pointing at. If you have a method chain that loaded a particular software item instance to be updated, pass the reference through the chain of methods as a parameter. This helps encapsulate the logic. You should also look to define a scope for whenever you are referencing a DbContext. With Blazor this needs to be done a bit more explicitly to avoid DbContext instances from being too long-lived. Long-lived DbContext instances are a problem because they lead to performance degradation as they track increasing numbers of entities, and can easly become "poisoned" with invalid entities that prevent things like SaveChanges() calls from succeeding. Keep instances alive only as long as absolutely necessary. I would strongly recommend looking at unit of work patterns to help encapsulate the lifetime scope of a DbContext. Ideally entities loaded by a DbContext should not be passed outside of that scope to avoid issues and complexity with detached or orphaned entities.
Next, it is important to know when you are looking to create new entities vs. reference existing data. Code like this is a big red flag:
Author addedAuthor = new Author();
addedAuthor.Programmer = new Programmer();
addedAuthor.Programmer.ProgrammerId = author;
From what I can make out, the Author (and Maintainer) are linking entities so we will want to create one for each "link" between a software item and a programmer. However, Programmer is a reference to what should be an existing row in the database.
If you do something like:
var programmer = new Programmer { ProgrammerId == author };
then associate that programmer as a reference to another entity, you might guess this would tell EF to find and associate an existing programmer.. Except it doesn't. You are telling EF to associate a new programmer with a particular ID. Depending on how EF has been configured for that entity (whether to use an identity column for the PK or not) this will result in one of three things happening if that programmer ID already exists:
A new programmer is created with an entirely new ID (identity gives it a new id and ProgrammerId is ignored)
EF throws an exception when it tries to insert a new programmer with the same ID. (Duplicate PK)
EF throws an exception if you tell it add a new programmer and it happens to already be tracking an instance with the same ID.
So, to fix this, load your references:
List<int> authorIdsToAdd = new List<int>();
// likely need logic to only add authors if they are selected, and unique.
authorIdsToAdd.Add(Author1);
authorIdsToAdd.Add(Author2);
authorIdsToAdd.Add(Author3);
// Define your own suitable scope mechanism for this method or method chain
using (var context = new AppDbContext())
{
var softwareItem = new SoftwareItem { /* populate values from DTO or Map from DTO */ }
// Retrieve references
var authors = await context.Programmers.Where(x => authorIdsToAdd.Contains(x.ProgrammerId)).ToListAsync();
foreach(var author in authors)
{
softwareItem.Authors.Add(new Author { Programmer = author });
}
// Continue for Maintainers...
await context.SaveChangesAsync();
}
I have a problem creating a related entity in Entity Framework Core 2.0. I've just created the solution, consisting of an Asp.Net Core backend project, and a UWP project to act as client. Both solutions share model. The two models are:
public class UnitOfWork {
public int UnitOfWorkId { get; set; }
public string Name { get; set; }
public Human Human { get; set; }
}
public class Human {
public int HumanId { get; set; }
public string Name { get; set; }
public List<UnitOfWork> WorkDone { get; set; }
}
As you can see, model is very simple. One human has many units of work. By the way, the backend is connected to an Azure SQL database. I've seen the migration classes, and the database schema looks good to me.
The problem I have is when I want to create a unit of work referencing an existing human, using HTTP. The controller is fairly simple:
[HttpPost]
public UnitOfWork Post([FromBody] UnitOfWork unitOfWork) {
using (var db = new DatabaseContext()) {
db.UnitsOfWork.Add(unitOfWork);
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
}
return unitOfWork;
}
Again, nothing fancy here.
How can I create an unit of work, and assign it to an existing human? If I try it with an existing human, in this way
var humans = await Api.GetHumans();
var firstHuman = humans.First();
var unitOfWorkToCreate = new UnitOfWork() {
Name = TbInput.Text,
Human = firstHuman,
};
I get this error:
Cannot insert explicit value for identity column in table 'Humans' when IDENTITY_INSERT is set to OFF
I feel that setting IDENTITY_INSERT to ON will solve my problem, but this is not what I want to do. In the client, I'll select an existing human, write down a name for the unit of work, and create the latter. Is this the correct way to proceed?
EDIT: Following #Ivan Stoev answer, I've updated the UnitOfWork controller to attach unitofwork.Human. This led to
Newtonsoft.Json.JsonSerializationException: 'Unexpected end when deserializing array. Path 'human.workDone', line 1, position 86.'
Investigating - seen here - EFCore expects to create collections (like human.WorkDone) in the constructor, so I did it, and no more nulls deserializing. However, now I have a self-referencing loop:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected with type 'PlainWorkTracker.Models.UnitOfWork'. Path 'human.workDone'.
Any ideas? Thanks!
The operation in question is falling into Saving Disconnected Entities category.
Add methods marks all entities in the graph which are not currently tracked as new (Added) and then SaveChanges will try to insert them in the database.
You need a way to tell EF that unitOfWork.Human is an existing entity. The simplest way to achieve that is to Attach it (which will mark it as Unchanged, i.e. existing) to the context before calling Add:
db.Attach(unitOfWork.Human);
db.Add(unitOfWork);
// ...
I have created a fairly simply domain model using pocos. I have mapped these to an EF DB context using EntityTypeConfiguration<TEnitityType> classes. This all works fine.
I am now trying to create an OData V4 WebAPI controller endpoint using a ODataConventionModelBuilder and this is where things are coming unstuck. It all works fine until it encounters an association that is not convention based. But I cannot find a way to get the ODataBuilder to pick up the mappings from my EntityTypeConfiguration<TEnitityType> classes.
This leaves my with 2 unpalatable options
Decorate my lovely clean pocos with dirty attributes.
Re-map all the non convention based mappings manually using the ODataBuilder
Not sure if code samples will help but here they are anyway, i have simplified the entities for brevity.
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Item>("Items");
config.MapODataServiceRoute(
routeName: "odata",
routePrefix: "odata",
model: builder.GetEdmModel(),
batchHandler: new DefaultODataBatchHandler((GlobalConfiguration.DefaultServer)));
public class Item
{
public Int32 Id { get; set; }
public Int16 ItemTypeId { get; set; }
public virtual ItemType Type { get; set; }
public virtual ICollection<ItemVersion> Versions { get; set; }
public virtual ICollection<ItemTag> Tags { get; set; }
}
The problem comes when it encounters the ItemTags collection, here is an ItemTag:
public class ItemTag
{
public Int32 ItemId { get; set; }
public string Tag { get; set; }
public Item Item { get; set; }
}
Which you can see is not convention based and I have a configuration class for it as follows:
public class ItemTagConfiguration : EntityTypeConfiguration<ItemTag>
{
public ItemTagConfiguration()
{
HasKey(x => new {x.ItemId, x.Tag});
HasRequired(x => x.Item)
.WithMany(y => y.Tags)
.HasForeignKey(x => x.ItemId);
}
}
Does anyone know of a way that I can use these EntityTypeConfiguration files with an ODataBuilder or web API?
EDIT
If found this page which seems to indicate it might be possible with EF 6 which I am using. What I want to do is this
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Dbf>("Dbfs");
// modelBuilder.Configurations.Add(new DbfMap()); <---- NO GOOD - Needs Class from DBContext we only have a model builder :(
Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "odata", model);
but the builder does not have a Configurations property.
Two things:
I have read multiple sources now that ward against using lazy loading and serialization; which is basically what OData is; (It even uses the system.runtime.serialization.datacontract and datamember attributes)
I have had more success in explicitly loading from context, and defining navigation properties in the modelbuilder for dbContext. I understand you are looking at customized nav properties, but I am fairly sure these are overriden methods useful for the ODataModelBuilder class (that does not assume much and needs less Entity Framework to work). Where you mentioned using EF already, I imagine that is the direction you will work, and if you do not need to alias your model names, you add an entry for each Set, using convention naming.
EntitySet("routePrefixName")
in building the EdmModel, and it wires up the relationships you made using Fluent previously. If you do have to add extraneous items to the underlying model, you should define each class as an EntityType<>(), only setting the key. EdmBuilder can use mild properties and key association to attach to the EF model in the ODataConventionModelBuilder.
I have wrestled and sought for some time, and there does not seem to be a wealth of information on .Net OData v4 floating around, probably due to the whole force datetimeoffset issue.
Hope that helps somewhat
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.