for ( int i = 0; i < libraryList.Count; i++)
{
if (ModelState.IsValid)
{
context.Library.Add(libraryList[i]);
context.SaveChanges();
}
}
A library contains an entity 'predefinedgoals' which is already set up in the DB. So when the above code runs it stores dublicates of 'predefinedgoals' and assigns new ID's to them.
I read that I should attach the existing entity to the context but I'm not sure how to to do it in my scenario. The classes look like this:
class library
int libraryID
list<book> bks
.
class book
int bookID
list<importantdates> impdts
.
class importantdate
int importantdateID
predefinedgoal predfg
int numberofresellers
.
class predefinedgoal
int predefinedgoalID
string description
int daysfrompublication
I tried something like this right after ModelState.IsValid but I sense I'm doing it wrong:
var prdfgs= context.predefinedgoals.ToList();
foreach(var pg in prdfgs)
context.predefinedgoals.Attach(pg);
This answer is going to be based on a couple of assumptions, but I've seen this exact problem so many times that this is automatically my go-to answer.
What I think you're doing is that you're creating Library, Book, and ImportantDate objects (and setting up all of the relationships between them as well). In the process of doing all of this, however, you are trying to set the PreDefinedGoal navigational property on those ImportantDate objects, all the while leaving the actual int FK property (that would be something like PreDefinedGoalID), still set to 0. When that happens, Entity Framework disregards the fact that the object contained in the navigational property has an ID on it, and assumes that you are trying to create this PreDefinedGoal object from scratch, just like you're creating the ImportantDate object (as well as the others). It will then create a PreDefinedGoal object with the exact same data as the one you're actually trying to use, but it will create it as a separate, duplicate record in the database.
The solution to your problem then is simple: Don't set the navigational property. Just simply set the FK (ImportantDate.PreDefinedGoalID) to the ID of the PreDefinedGoal object that you want to hook up to it. When you do that, and you save it, Entity Framework will then reach out to the database for the correct object based on that ID, and thus you will avoid having duplicate PreDefinedGoal objects in your database.
FYI: I learned this from one of Julie Lerman's MSDN posts. If you're going to be working with EF, I highly recommend reading her posts and columns.
I am in the same situation and found a workaround. The way this workaround works makes me think that in this case EF is to blame for handling the situation badly.
In order to simplify the example I will just post an example with one object and it's navigational property.
public class Topic
{
int Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
}
public class Course
{
int Id { get; set; }
public Topic Topic { get; set; }
// additional properties don't matter now
}
Note the absence of any foreign key or other data annotations. EF6 will correctly create the database schema from this and infer that Id is the primary key.
Without workaround adding a new course for an existing topic will create a new topic object with a new Id (overwriting the Id it was given!) :
db.Courses.Add(course);
await db.SaveChangesAsync();
The braindead workaround:
course.topic = db.Topics.Find(course.topic.Id);
db.Courses.Add(course);
await db.SaveChangesAsync();
In other words, if the topic has been loaded from the context directly, EF will recognize it as an existing topic and don't try to add it again.
Update: To just attach the entity without reloading it:
db.Topics.Attach(course.topic);
However you will run into more issues with this setup, it is probably best to use ForeignKey attribute(s) and include the TopicId in Course object. Following works OK but still looks ridiculous to me:
[ForeignKey("Topic")]
public int TopicId { get; set; }
[ForeignKey("TopicId")]
public virtual Topic Topic { get; set; }
Would love to hear about a less redundant solution though.
The answer to why it stored duplicates in my scenario was that I performed tasks in two different classes - using different database context variables in each of them.
So class #1 is the one in my question, that's where I'm saving to the DB using context #1. In class #2 I retrieved all the PredefinedGoals and added them to ImportantDates but to do this I created context #2. The ID's and objects were the same but retrieved from different context variables.
I solved it by retrieving the PredefinedGoals in class #1 with context variable #1 and sent them as an argument to class #2.
Related
I'm using EF5 Code First with :
public class Scenario
{
public int Id { get; set; }
public IList<Client> Clients { get; set; }
}
public class Client
{
public int Id { get; set; }
public string Name {get;set;}
public int VisibilityNumber{ get; set; }
}
I'm directly sending the scenario object to the view (MVC4, without using a viewmodel class - maybe a mistake ?, but a lot less plumbing code). In my view, I use HiddenFor for Scenario.Id, and a for loop to display an EditFor for each client VisibilityNumber.
This is the Controller :
[HttpPost]
public ActionResult Edit(int id, FormCollection formValues)
{
if (ModelState.IsValid)
{
Scenario scen=GetScenarioFromDB(id);
TryUpdateModel(scen,formValues);
if (ModelState.IsValid)
SaveToDb(scen);
}
}
After the TryUpdateModel, for each Clients object (which were correctly loaded from DB) :
VisibilityNumber is correctly set
Id is set to 0, which of course is a bad thing
Name is set to null
After looking at the MVC Source code (DefaultModelBinder/UpdateCollection), I can see that when binding to collections, new items are always created.
If I can't fix that, I think I'm going to use a viewModel, and AutoMapper. I assume that the MVC team wanted to force us to use viewModel, rather than directly send EF object.
You should not get scenario from database in your update. Instead, you should take your bound model, attach it (if edited) or add it (if new) to context and then save changes. It's a common scenario called "disconnected entities" (which you, in fact, do have, because you have model that was disconnected when sent to client, and then got back also disconnected).
I "fixed" DefaultModelBinder/UpdateCollection so that it can work with my use case : when the binding is drilling down in the navigation properties, it uses the current object as model (it's easy, since I'm only doing modifications, no insert or delete) : I can take the DefaultModel source code, put my fix in it, and use it as a custom model binder. It's fun, but a bit dirty and over the top.
But I believe the best way is to use a specific ViewModel, using only the properties which are editable, and use AutoMap to map it to my EF hierarchy. BUT : it has the same problem of creating child objects collection.
In the end, I just did some manual mapping for between my View Model and my EF hierarchy : I'm nearly sure I can do something automatic, which could detect if a child item has been modified or inserted or deleted (since every item has a [key] property, but I just don't have the time budget to implement it.
In my ASP.NET MVC project, my actions typically call a Service layer to get data. I use the same dozen or so POCOs for all my models. I also plan on using the Service layer in console applications and maybe expose a web api at some point.
To make my database operations more efficient, my service layer only hydrates the properties in the model that are relevant to the particular method (which at this point is mostly driven by the needs of my controller actions).
So for example I might have a class Order with properties Id, Name, Description, Amount, Items. For a given service call I might only need to populate Id, Name, Items. A consumer of that service won't necessarily know that Amount is 0 only because it didn't populate the property.
Similarly, the consumer won't know whether Items is empty b/c there actually aren't any items, or whether this particular service method just doesn't populate that property.
And for a third example, say one of my views displays an ItemCount. I don't want to fully populate my Items collection, I just need an additional property on my "model". I don't want to add this property to my POCO that other service methods will be using because it's not going to be populated anywhere else.
So the natural solution is to make a POCO designed specifically for that method with only those 3 properties. That way the consumer can know that all properties will be populated with its real values. The downside to this is that I'll end writing tons of similarly shaped models.
Any advice on which method works best?
You could use Nullable Types to indicate the missing properties with a null.
For example:
class Order {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal? Amount {get;set;}
public List<Item> Items {get;set;}
}
And then if Items == null, it wasn't set. If it's an empty new List<Item>(), it's set but empty. Same for Amount. If Amount.HasValue == false, it wasn't set. If Amount.Value is 0.0d, it's set and the item is free.
Why don't you use LINQ projection?
One service method does something like:
return DbContext.Orders.Select(o => new { Id = o.Id, Name = o.Name, Description = o.Description });
while the other service method does something like:
return DbContext.Orders.Select(o => o);
I'm not sure how your application is architected, but this may be a way around creating 100's of POCO's.
Hope this helps! Good luck.
You could pass in a selector Func that returns dynamic:
public IEnumerable<dynamic> GetOrders(Func<Order, dynamic> selector) { ... }
I'm not sure how you are accessing data, but the following shows how this would work using a List<T>:
class Program
{
static void Main(string[] args)
{
var service = new Service();
var orderNames = service.GetOrders(o => new { o.Name });
foreach (var name in orderNames)
Console.WriteLine(name.Name);
Console.ReadLine();
}
}
public class Service
{
private List<Order> _orders = new List<Order>
{
new Order { Id = 1, Name = "foo", Description = "test order 1", Amount = 1.23m },
new Order { Id = 2, Name = "bar", Description = "test order 1", Amount = 3.45m },
new Order { Id = 3, Name = "baz", Description = "test order 1", Amount = 5.67m }
};
public IEnumerable<dynamic> GetOrders(Func<Order, dynamic> selector)
{
return _orders.Select(selector);
}
}
public class Order
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
}
The use of nullable values is a good solution, however it has the downside you have no way to matk required fields. That is you cannot use a required attribute on any property. So if there is field that is obligatory in some views you have no way to represent it.
If you don't need required fileds validation this is ok. Otherwise, you need a way to represent which fileds are actually used, and then to write a custom validation provider.
A simple way to do this is to use a "Mask" class with the same property names of the original class, but with all fields boolean: a true values means the field is in use.
I used a similar solution in a system where the properties to be shown are configured in a configuration files...so it was the unique option for me since I had no possibility to represent all combination of properties. HOWEVER, I used the "Mask" class also in the View, so I was able to do all the job with just one View..with a lot of ifs.
Now if your 150 service methods and probably about 150 Views...are all different, then maybe it is simpler to use also several classes ...that is in the worst case 150 classes..the extra work to write them is negligible if compared to the effort of preparing 150 different Views.
However this doesnt mean you need 150 POCO classes. You might use an unique POCO class that is copied into an adequate class just into the presentation Layer. The advantage of this approach is that you can put different validation attributes on the various classes and you don't need to write a custom Validation provider.
Return the entire POCO with nullable types as mentioned by #sbolm. You can then create a ViewModel per MVC page view that receives a model with the specific properties it needs. This will take more performance (insignificant) and code, but it keeps your service layer clean, and keeps your views "dumb" in that they are only given what they need and have no direct relation to the service layer.
I.e. (example class from #sbolm)
class Order {
public int Id {get;set;}
public string Name {get;set;}
public string Description {get;set;}
public decimal? Amount {get;set;}
public List<Item> Items {get;set;}
}
// MVC View only needs to know the name and description, manually "map" the POCO properties into this view model and send it to the view
class OrderViewModel {
public string Name {get;set;}
public string Description {get;set;}
}
I would suggest that instead of modifying the models or creating wrapper models, you have to name the service methods such that they are self-explanatory and reveals the consumer what they returns.
The problem with the nullable approach is it makes the user to feel that the property is not required or mandatory and they try inserting instances of those types without setting those properties. Is it won't be bad having nullables every-where?
It won't be a good approach to change the domain models since all you want is just to populate some of the properties instead of that you create service with names and descriptions that are self-explanatory.
Take the Order class itself as the example, say one service method returns the Order with all the items and the other one returns only the details of the Order but not the items. Then obviously you may have to create two service methods GetOrderItems and GetOrderDetail, this sounds so simple, yes it is! but notice the service method names itself tells the client what it is going to return. In the GetOrderDetail you can return an empty items or null (but here I suggest a null) that doesn't matter much.
So for new cases you don't need to frequently change the models but all you got to do is add or remove the service methods and that's fine. Since you are creating a service you can create a strong documentation that says what method does what.
I would not performance optimize this to much unless you realy get performance problems.
I would only distinguish between returning a flat object and an object with a more complete object graph.
I would have methods returning flat objects called something like GetOrder, GetProduct.
If more complete object graphs are requested they would be called : GetOrderWithDetails.
Do you use the POCO classes for the typed views? If yes: try to make new classes that serve as dedicated ViewModels. These ViewModels would contain POCO classes. This will help you keeping the POCO classes clean.
To expand on the nullable idea, you could use the fluentvalidation library to still have validation on the types dependent on whether they are null or not. This would allow you to have a field be required as long as it was not null or any other validation scheme you can think of. Example from my own code as I had a similar requirement:
Imports FluentValidation
Public Class ParamViewModelValidator
Inherits AbstractValidator(Of ParamViewModel)
Public Sub New()
RuleFor(Function(x) x.TextBoxInput).NotEmpty.[When](Function(x) Not (IsNothing(x.TextBoxInput)))
RuleFor(Function(x) x.DropdownListInput).NotEmpty.[When](Function(x) Not (IsNothing(x.DropdownListInput)))
End Sub
End Class
I believe this is an AutoMapper basics question:
I have an single "article" Entity Framework entity that I am mapping to a viewmodel to pass to a view for edits. This works fine:
Mapper.CreateMap<Article, ArticleAdmin>();
var articleData = Mapper.Map<Article, ArticleAdmin>(articleEntity);
Now, my EF model includes many-to-many relation to a Topics table via a TopicArticles lookup table, and I want to manage associations when I'm editting the article data.
So I add this to my viewmodel:
public ICollection<TopicArticle> TopicArticles { get; set; }
I believe this is correct specification to mirror the entity type -- my EF model has the TopicArticles association member as an EntityCollection.
and I add a second viewmodel class to populate the list:
public class TopicArticle
{
public int ArticleId { get; set; }
public int TopicId { get; set; }
public bool IsPrimaryTopic { get; set; }
}
When I run the mapping, I get "Missing type map configuration or unsupported mapping." Which is understandable as I've not told Automapper about my TopicArticle viewmodel class.
So:
QUESTION:
How do I change my mapping to account for this extra layer?
(I don't really understand the Automapper syntax for how this should be mapped.)
Also: have I missed anything else?
NOTE / UPDATE:
There were some errors in my posted code, any "publication" that appeared was incorrect, and should have been "article" -- that was because I'm simplifying the situration a bit: articles actually inhereit from publications, but I did not want that complexity in this Question.
OK, this really is basic. My problem was not getting to the actual Automapper documentation. Googling "automapper documentation" gets this link as the top response:
http://automapper.codeplex.com/documentation
which is a useless TOC.
The real documentation is accessed from the home page.
The answer to my question is simple:
First, I change the name of my second viewmodel class for clarity:
public class TopicArticleAdmin
Then back in my action, I add one more mapping line:
Mapper.CreateMap<Publication, ArticleAdmin>();
Mapper.CreateMap<TopicPublication, TopicPublicationAdmin>();
var articles = Mapper.Map<IEnumerable<Publication>, IEnumerable<ArticleAdmin>>(
articleEntities
);
I am using Code First to automatically generate my database, and this works perfectly, generating an Orders table and an OrderLines table as expected when I add some test data.
I have the following Order class:
public class Order
{
public int OrderID { get; set; }
public void AddItem(string productCode, int quantity)
{
var existingLine = OrderLines.FirstOrDefault(x => x.ProductOption.ProductCode == item.ProductCode);
if (existingLine == null)
OrderLines.Add(new OrderLine { ProductOption = item, Quantity = quantity });
else
existingLine.Quantity += quantity;
}
public void RemoveItem(string productCode)
{
OrderLines.Remove(OrderLines.Where(x => x.ProductOption.ProductCode == productCode).FirstOrDefault());
}
public virtual ICollection<OrderLine> OrderLines { get; set; }
public Order()
{
OrderLines = new List<OrderLine>();
}
}
What I really want is to encapsulate the OrderLines collection, making it impossible for consumers of the class to directly add and remove items to/from it (using the Add / Remove methods of ICollection) and instead forcing them to use my custom AddItem and RemoveItem methods.
Normally I could just make the collection private, but I can't do that because it needs to be virtual for EF to correctly create the OrderLines table/foreign keys.
This answer seems to suggest that making the property internal would do the trick, but I tried, and in that case no OrderLines table is created.
Is there any way that this can be accomplished, or should I have designed this differently somehow? Any help much appreciated!
Update
After a bit more searching, I found this question which is rather more clearly stated than mine; however, it's still unanswered. The poster does link to this post which seems to suggest it can't really be done in the way I'm thinking of, but does anyone have any more up-to-date information?
I don't know if it's possible to do what you are asking or not, but I'm not sure it's the best design. The problem that I am seeing is you are firmly integrating your business logic into your business entities, and I think this will turn into confusion down the road.
Take the following scenario under consideration. Say you have a new requirement where you want users to be able to remove all items from an order. The only way to do it with your entity is to create a new RemoveAllItems() method to your Order class which does that. Now say you have a new requirement to Remove all items from an order that are in a specific category. That then means that you have to add yet another method.
This causes really bloated classes, and there is one major issue you will come up with. If you (or another developer) want to look at an entity and determine it's data structure, you can't at a glance because it's so intertwined with business logic.
What I would suggest is that you keep your entities as pure data structures, keeping all their relationships public. Then you need to create a service layer, which can consist of small or big classes (however you want to organize them) that actually perform the business functions. So for example, you can have a OrderItemService class, which has methods for adding, editing, and removing items from an order. All your business logic is performed in this class, and you just have to enforce that only service classes are allowed to interact with db entities.
Now, if you are looking for how a particular business process is performed, you know to look in the service layer classes, and if you want to look at how a data structure or entity is organized, you look at the entity. This keeps everything clean and very mantainable.
I'm far from an expert on code first and I haven't tried the following but is it possible to use the ReadOnlyCollectionBase and create a read only list similar to this MSDN article?
Well what you can do is set your collection as private and make the relationship using fluent API in the OnModelCreating, as shown below, I don't know if this will work, just make a try:
public class YourContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.HasMany(o => o.OrderLines)
.WithRequired(l => l.OrderId)
.HasForeignKey(l => l.OrderId);
}
}
This will make your OrderLines as readonly:
public class YourContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<OrderLine> OrderLines
{
get { return set<OrderLine>(); }
}
}
I hope this can help you, please take a look a this blog post: EF Feature CTP5: Fluent API Samples
This has been driving me nuts for a week now.
I have a class that looks like this:
public class SuggestionVote
{
public virtual int ID { get; set; }
public virtual Suggestion Suggestion { get; set; }
public virtual User User { get; set; }
public virtual VoteTypeWrapper VoteType { get; set; }
public virtual DateTime DateVoted { get; set; }
// Equality overrides omitted
}
VoteTypeWrapper is actually an enum wrapper based on an article on how to fake enums in Entity Framework 4 and looks like this:
public class VoteTypeWrapper
{
private VoteType _type;
public int Value
{
get { return (int)_type; }
set { _type = (VoteType)value; }
}
public VoteType EnumValue
{
get { return _type; }
set { _type = value; }
}
public static implicit operator VoteTypeWrapper(VoteType voteType)
{
return new VoteTypeWrapper { EnumValue = voteType };
}
public static implicit operator VoteType(VoteTypeWrapper voteTypeWrapper)
{
return voteTypeWrapper == null ? VoteType.NotVoted : voteTypeWrapper.EnumValue;
}
}
with the VoteType enumeration being:
public enum VoteType
{
Up,
Down,
NotVoted
}
I've also defined a ComplexType in the model designer:
<ComplexType Name="VoteTypeWrapper" >
<Property Type="Int32" Name="Value" Nullable="false" />
</ComplexType>
The voting system I'm implementing works somewhat like StackOverflow's voting system: The user can vote up or down; voting a second time undoes the previous vote, and voting in the opposite direction (i.e., down when previously voted up) undoes the vote as well.
Now for the problem. Voting once works like a charm and all the values are correctly saved to the database. Undoing a vote, however, refuses to work. To undo a vote I basically mark the vote to undo for deletion and then call SaveChanges on the context.
As soon as I do that an InvalidOperationException occurs giving me the following message:
The entity of type 'System.Data.Entity.DynamicProxies.SuggestionVote_4A3949F5B95E9A51567509467230FD7CEA0FB7761C3AC9C8C2BBC62BCAA033AF'
references the same complex object of type 'Web.Model.VoteTypeWrapper' more than once.
Complex objects cannot be referenced multiple times by the same entity.
I just don't get it. Down anyone know what I could be doing wrong? I've been Googleing for day but to no avail
Well, I've finally decided to work around it but simply mapping an int property instead of a ComplexType. I have also added a (non-mapped) helper property to avoid having to cast constantly from int to VoteType.
I would still love to get an answer for my problem so if you can help it I would appreciate it. I'll give it a couple of days before I mark my own answer as correct.
EDIT: Since I've gotten no answer whatsoever to this, m marking my own answer as good.
I've just encountered the same problem. I have a class that contains a complex type that contains another complex type. Let's call them Class1, Complex1 and ChildComplex. My scenario is the following (I don't know if it matches yours, but the error message is exactly the same).
I retrieve from the context an instance of Class1 and perform a change in a property of Complex1. I then call SaveChanges to the context and get the same exception :
The entity of type '<Class1>' references the same complex object of type '<Complex2>' more than once.
Complex objects cannot be referenced multiple times by the same entity.
I have not found a decent workaround other than cloning the Complex1 instance, replacing the cloned version in the Class1 instance and then making the change. That way EF does not complain that it's the same complex object.
This is a really strange behaviour. If I have time (around 2038) I'll try to isolate it and report it to MS, smells like a bug...
I've just been searching for this same issue, but I've just realized I was misreading the error. Its not complaining that your entity has two properties of the same type, its complaining that your storing the 'exact' same object of that type in both properties.
In my case I was doing a lookup on an table to get my complex type, and I now realize that if the lookup returned the same value it would be the same object.
I fixed this by creating a new object of my complex type and setting its values to the same as the lookup.