In an ASP.NET MVC application where I have the following model..
public class EventViewModel
{
public Guid Id { get; set; }
public List<Guid> Attendants { get; set; }
}
passed to a view...
public ActionResult Create(EventViewModel model)
{
// ...
}
I want to be able to add to the "Attendants" Collection from the View. The code to add it works just fine - but how can I ensure that the View model retains the list? Is there any way to do this without saving/opening/saving etc? I am calling my addition method via jQuery $.load.
public void Insert(Guid attendant)
{
// add the attendant to the attendees list of the model - called via $.load
}
I would also like to add there is no database. There is no storage persistence other than plain files.
If you are posting your data and want to re-display it, you have to round-trip your data back to the view.
To maintain multi-user data integrity, I typically save the data to the database, and then retrieve the data from the database again when passing it back to the view for redisplay.
Potentially, you can do something AJAX-y in the view to add records, so that you don't have to continually round-trip the entire dataset each time a record is added.
EDIT: Just noticed that you don't have a database. If your application is architected properly (i.e. you are using repositories), the method of backend storage shouldn't matter.
For more info on general practices for adding records, see the NerdDinner tutorial.
Related
I have following POCO class being used in EF 6.x.
My question: Why is the navigation property of 'Posts' under 'Blog' entity declared as virtual?
public class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Tags { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
If you define your navigation property virtual, Entity Framework will at runtime create a new class (dynamic proxy) derived from your class and uses it instead of your original class. This new dynamically created class contains logic to load the navigation property when accessed for the first time. This is referred to as "lazy loading". It enables Entity Framework to avoid loading an entire tree of dependent objects which are not needed from the database.
In some circumstances, it is best to use "Eager Loading" instead, especially if you know that you will be interacting with related objects at some point.
Julie Lerman really is the authority on all things Entity Framework, and she explains this process very well in her MSDN Article Demystifying Entity Framework Strategies: Loading Related Data
Eager loading with Include is useful for scenarios where you know in advance that you want the related data for all of the core data being queried. But remember the two potential downsides. If you have too many Includes or navigation paths, the Entity Framework may generate a poorly performing query. And you should be careful about returning more related data than necessary thanks to the ease of coding with Include.
Lazy loading very conveniently retrieves related data behind the scenes for you in response to code that simply makes mention of that related data. It, too, makes coding simpler, but you should be conscientious about how much interaction it’s causing with the database. You may cause 40 trips to the database when only one or two were necessary.
If you are developing a Web Application where every communication with the server is a new context anyway, Lazy Loading will just create unnecessary overhead to maintain the dynamic class for related objects that will never be loaded. Many people will disable lazy loading in these scenarios. Ultimately, it's still best to evaluate your SQL queries which EF has built and determine which options will perform best for the scenario you are developing under.
Below is the Project code-first class mapped directly to the database through the Entity Framework 6 Fluent API:
public class Project
{
public Project()
{}
public int ProjectId { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public ICollection<ProjectVersion> ProjectVersions { get; set; }
}
Anemic models in Domain-Driven Design are an anti-pattern. I want to use this same class in my domain model instead of creating a separate Project domain class and having to perform complicated mapping between the two in the repository (and with the hundreds of other models we have).
This is how Project would look as a domain model class:
public class Project
{
private readonly List<ProjectVersion> projectVersions;
public Project(string name, string description)
{
Name = name;
Description = description;
projectVersions = new List<ProjectVersion>();
}
public int ProjectId { get; private set; }
public string Name { get; set; }
public bool IsActive { get; private set; }
public IEnumerable<ProjectVersion> ProjectVersions
{
get
{
return projectVersions;
}
}
public void AddVersion(ProjectVersion version)
{
projectVersions.Add(version);
}
}
From what I have read, I am able to map to a private fields with EF's Fluent API.
Are there any any shortcomings here? Am I taking an unnecessary shortcut?
The only problem I can forsee is when a business domain model would essentially consist of data from two or more data entities.
I think you're making a mistake in this approach. I think you should separate the concerns of your Domain models from the concerns of your Entity models. Uncle Bob wrote a strange, but on-point blog post about this here: Dance You Imps! (seriously, it's a weird post.) The ORM's job is to act as a contract to your database. Your domain models' job is to provide the functionality. In short, you should let Entity Framework function the way it wants to. If you want to do DDD, write a mapping layer to convert EF models to your Domain models.
Are there any any shortcomings here?
Possibly.
It is true that EF can address private members, so it is able to materialize a Project with a loaded ProjectVersions collection if you want. It won't use the AddVersion method for that (it doesn't even know it exists), but it will add objects to the projectVersions member.
In the application code you want to add versions through a method. There may be some problems with this AddVersion method though.
You can always add a ProjectVersion, but you will never be sure whether it will be stored, because for EF to track the addition projectVersions must have been loaded. However, you don't want a domain entity to be responsible for loading its own children from the database. So AddVersion gives the class a responsibility it can't fulfil to the full.
Calling AddVersion can occur any moment during the lifespan if the object. Usually this will be longer than the lifespan of the context by which it was created and tracked. So you can't rely on lazy loading to come to the rescue if the collection is not loaded yet. (ProjectVersions should virtual ICollection for that, by the way).
The conclusion is that you always have to load projectVersions eagerly (through Include) for AddVersion to be guaranteed to work properly. So there is a dependency in your application between two not obviously related pieces of code, which is a potential source of bugs.
When it is time to save the Project, you have to attach it to a context and find out which ProjectVersion should be marked for insert and which for update (and there's not even a RemoveVersion method yet.
All in all, it is much simpler to add versions in a service method that does all required actions within the lifecycle of a context. An added version will be marked for insert automatically. Likewise, any updated and deleted version will be marked correctly.
I'm working on a MVC4/EF5 project and I really want to invest a lot of time in the design of my application.
I have made one policy/principle for myself. My controllers need to be dedicated, which means they can only interact with one specific repo.
E.g. (I'm just writing some pseudo code)
objects: User, Blog, Post, Comment
UserController -> UserRepo -> Handles the User object
BlogController -> BlogRepo -> Handles the Blog object
etc...
Now I'm looking into the following dilemma. What's the most performant to create/add new objects to the database with EF5.
1st Approach:
Add a function to User to add a Blog or add a Post.
addBlog(Blog b){this.Blog.addBlog(b);}
addPost(int blogid, Post p){this.Blog(b).addPost(p);}
For me this means that every post will initiate a usercontroller, inject a userrepo and will have a read operation in the User table to fetch the object. Then it will perform the addPost function and saves the changes.
2nd Approach:
Give the Blog and Post object some foreign key ids
Blog property: UserId
Post property: UserId, BlogId
This means whenever a blog is created, a blogcontroller will be initiated, a blogrepo will be injected and there is no 'LOOKUP' needed. The controller will just add the new Blog object to the context. (the UserId property is set from the websecurity context)
This also means that whenever a post is created, a postcontroller will be initiated, a postrepo will be injected and there is no 'LOOKUP' needed. The controller will just add the new Post object with the injected UserId and BlogId. (which are parameters of the controller action)
For me the second approach seems to devide the load on different tables instead of one. But the downside of this approach is that you can't really do model testing. Because there would be no function addBlog to the User object to be tested.
Is my question somewhat clear? I really want to build the most performant framework for my application. Also what is the impact of a User object with the following properties.
Virtual ICollection
Virtual IColleciton
They can both be retrieved by fetching the User object. (then there is lazy loading on the virtual objects)
Or is it better to let the dedicated BlogController index the blogs that belong to a certain user id.
Thanks a lot for all the advice and comments!
Kr
After investigating the created entity framework statements with SQL Profiler, I came to the conclusion that it doesn't matter how you create a new object.
Adding a new object directly to the repo creates the SAME insert statement as when you add the object through a collection of another object.
public class Blog
{
public int Id { get; set; }
public virtual ICollection Articles { get; set; }
}
public class Article
{
public int Id { get; set; }
}
I am using Entity Framework 5 with Code First approach and using Fluent API for Entity configuration. My project has one particular Product Entity which gets half of its data from the database and the other half from a Data Contract retrieved via a WCF Client (its a 3rd party system used to manage product inventory). The Data Contract is a member of the Product Entity class (property or method I haven't decided yet).
I prefer not to have any WCF Client logic contain within the Entities. I'd prefer to keep this logic in Repository code (DbContext, DbSet, etc.).
So is there a technique to hook into Entity Framework (or intercept) just after a Product Entity is retrieved from the database? I should note the Product Entity appears as a navigation property on other Entities. If a hook or intercept is possible then what that means is I can retrieve the Data Contract from the SOAP service immediately after EF loaded the Product Entity from the database. The benefit for my project is the WCF Client retrieval code does not need to be repeated throughout the application.
One idea I had was to implement IDbSet for the Data Contract and the IDbSet would be responsible for retrieving it. And then somehow trick EF into thinking its a navigation property on the Product Entity. But I wasn't sure if a database DbSet can be mixed with a non-database IDbSet all within the same DbContext. And also the other question - how would EF know to retrieve a navigation property from the IDbSet implantation? I'd prefer to know if this idea is possible before investing time into it. I'd also prefer to know where to start looking.
Please note I've been working with .NET for over 10 years but this EF5 stuff is still relatively new to me.
Thanks in advance.
-Sam
Today I found an event in the Entity Framework that seems to be what I am looking for. ObjectContext.ObjectMaterialized Event. Apparently, DbContext implements IObjectContextAdapter which in-turn exposes the ObjectContext. From there I can subscribe to the ObjectMaterialized event.
MSDN Reads:
Occurs when a new entity object is created from data in the data
source as part of a query or load operation.
The following code demonstrates how I used the ObjectMaterialized event to solve my problem in which one of my preferences was to have a central point to place the WCF client access logic.
// seperate assembly - does not use Domain.Repositories assembly
namespace Domain.Models
{
// the data contract
[DataContract]
public class ProductInventoryState
{
[DataMember]
public int StockStatus { get; set; }
[DataMember]
public IEnumerable<String> SerialNumbers { get; set; }
// etc....
}
// the entity
public class Product
{
public Guid Key { get; set; }
public string ProductCode { get; set; }
public ProductInventoryState InventoryState { get; set; }
// etc....
}
}
// seperate assembly - uses Domain.Models assembly
namespace Domain.Repositories
{
public class MainRepository : DbContext
{
public MainRepository()
{
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += ObjectContext_ObjectMaterialized;
}
protected void ObjectContext_ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
{
if (e.Entity == null)
return;
if (e.Entity is Product)
{
Product product = (Product)e.Entity;
// retrieve ProductInventoryState from 3rd party SOAP API
using (ThirdPartyInventorySystemClient client = new ThirdPartyInventorySystemClient())
{
// use ProductCode to retrieve the data contract
product.InventoryState = client.GetInventoryState(product.ProductCode);
}
}
}
}
}
1.) You can write your own EF Provider (but that is no small task)
2.) You can attach items to the context but not save them.
The entity.State can be set as Not modified after attaching.
You could also remove such entries from Context prior to save changes
3) You can Write a repository fascade that check EF and Checks location 2 and combines the result.
On the question of navigation properties.
You would need to specify these very carefully to avoid issues. Not lazy loaded or not even modelled.
I wouldnt try and mix them personally.
You can tell EF to ignore some properties.
So you can have a Nice original POCO, but only model the bits that are on the DB.
The POCO would then collect the rest.
I use a fascade with events myself to act on KEY methods on a context/DBset.
So I can trigger events on attach , get, save etc.
good luck
I'm building a Mobile MVC application and stumbled across many problems but this is bugging me a lot.
This is a Message class i'm reffering to:
public class Message
{
public int MessageID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Recieved { get; set; }
[ForeignKey("User")]
public int AuthorUserID { get; set; }
//P\\ Navigation properties
public virtual ICollection<MessageRecipient> MessageRecipients { get; set; }
public virtual User User { get; set; }
}
I create the new Message object and save it in database.
messageService.AddMessage(newMessage);
Message freshMessage = messageService.GetNewestMessage();
At this point it has no Recipients attached. User Gets redirected to a View where (s)he can add recipients to a message.
Whe the user add the recipient i invoke the method through ajax that creates the MessageRecipient object and adds it to the Recipients collection of the message.
message.MessageRecipients.Add(recipient);
The ideal situation would be: when the user finished adding recipients and goes back to the Edit View, added recipients are visible.
When Edit action is being invoked the GetMessage method is invoked
Message message = messageService.GetMessage(id);
Because this message has been retrieved before it would be held in ObjectContext, so EF would serve me the entity from the memory rather than query DB for fresh one and this is what i want to happen. I do not know how to save the changes in that ObjectContext without saving changes to Db by invoking SaveChanges().
So my question is: Is there a way to change the state of the entity held in a memory so next time when it's been queried for i get the entity with the changes i have made to it?
I just want to work with the object and save it to Db when i've done with it rather than make a trip to Db each time user adds a recipient to a message.
I'm new to .NET and EF...
Any help would be appreciated.
Because this message has been retrieved before it would be held in
ObjectContext, so EF would serve me the entity from the memory rather
than query DB for fresh one.
No it will not be held in the context unless you are sharing context among requests. You should use a new context for every request (even every Ajax request). There are multiple reasons why you should not share the context. Count one additional - leaking context equals leaking memory.
So my question is: Is there a way to change the state of the entity
held in a memory so next time when it's been queried for i get the
entity with the changes i have made to it?
Yes there is a way but it has nothing to do with EF. You must held your detached Message in session or in other store making your application workflow statefull and persist the message to database using EF only when the whole editing is complete.