How to retrieve original value of collection - entity-framework

I have a collection mapped in my model:
public class Project
{
// ...
public virtual ICollection<ProjectSupplier> ProjectSuppliers {get; set;}
}
And I want to retrieve original value of ProjectSuppliers collection (I know for sure that it has been loaded). I tried:
var originalProjectSuppliers = _context.Entry(project)
.OriginalValues
.GetValue<ICollection<ProjectSupplier>>("ProjectSuppliers");
But it gives me error:
System.ArgumentException : The 'ProjectSuppliers' property does not exist or is not mapped for the type 'Project'
I also tried getting DbCollectionEntry like that:
_context.Entry(project).Collection(p => p.ProjectSuppliers)
But it doesn't contain OriginalValues, only current ones.

Apparently this is the only way. Not what I would have hoped either, but the answer is written by a guy who works on Entity Framework, so I guess he would know.
UPDATE
Based on the linked answer above, I've built something perhaps more in line with your actual question, or at least you can use it to get back the original collection. I'm not sure it's the best way though, so I posted my own question on how to do it better.

Related

Do you need to load contents of Entity Framework collection before you .Add() to it?

I have an entity model with
class Package
{
...
virtual ICollection<Owner> Owners { get; set; }
}
and am implementing an AddOwner() operation.
Does the entity framework require me to retrieve my Package object including owners with .Include(p => p.Owners) in order for me to call p.Add(newOwner); and save changes back to the database?
Secondary question : Intuition isn't guiding me to an answer here because I don't know whether to base my intuition on CLR collections or on some principle of Entity Framework; is there a principle of EF that helps me understand things better than thinking in terms of CLR collections?
As long as your Package object is attached to a context, the Owners property will be set to an EntityCollection<Owner>. Regardless of whether it's loaded, changes through that property will be marked as changes in your context, and SaveChanges() will save those changes.
Keep in mind that your Owner object already needs to be part of the context, if it is an existing owner, though. If it is not, EF will assume you are trying to save a new Owner.
Owners will have to point to something concrete sooner or later, and certainly before you try adding anything to it. EF knows to look at this property through the ICollection interface.
You could do something such as:
var p = new Package { SomePackageProperty = "Some value",
Owners = new List<Owner>>() { new Owner { SomeOwnerProperty = "Some other value" } } };
yourContext.DbSet<Package>().Add(p);
But that's just a best guess, given the small snippet provided in the question.
I think you are thinking of including Owners .Include(p => p.Owners), and then saying p.Owners.Add(new_owner) to add a new Owner, which will work after .SaveChanges.

What is the best way to prevent updating on specific fields in Entity Framework

Im writing an web application with MVC using Entity Framework for my backend logic. My problem is that I have an entity that has certain fields that should never be changed on an update. I am not really sure what the best way to solve this problem would be. There is going to be a lot of data processed in my application, so I cant afford to just hack up a solution.
Is it possible to just define the fields as readonly in the POCO entities ? Or should I write and entity framework extension class that validates all updates. Could it be done in the mapping files between EF and the actual database?
I am relatively new with EF, so I hope some of you might be able to give me some pointers!
Thanks!
If you are using .NET 4.5 and EF 5 (i.e. MVC 4), you can simply set IsModified = false on the individual properties in question. This has the benefit of sticking close to the default out-of-the-box MVC conventions.
For example, if you have a CreatedBy field that shouldn't be touched when the record is updated, use the following in your controller:
[HttpPost]
public ActionResult Edit(Response response)
{
if (ModelState.IsValid)
{
db.Entry(response).State = EntityState.Modified;
db.Entry(response).Property(p => p.CreatedBy).IsModified = false;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(response);
}
Note that the IsModified line is the only change from the default controller action.
You MUST put this line AFTER setting .State = EntityState.Modified (which applies to the record as a whole and adds the record into the db context).
The effect is that EF will not include this column in the SQL UPDATE statement.
I am still (very) shocked that there are no [InsertOnly] or [UpdateOnly] attributes similar to [ReadOnly]. This seems like a major oversight by the MVC team. Am I missing something?
I'm not fully satisfied with this solution because it's a hack: You're telling EF that no change was made when what you really mean to say is "HANDS OFF". It also means that you have to use this code anyplace where the field could be updated. It would be better to have an attribute on the class property.
(Apologies for posting to an older thread, but I've not see this solution anywhere else. ViewModels are robust but a lot of work, and EF was supposed to make things easier, not harder...)
Well I would advice against ever using the EF classes in the View. You're best bet is to construct ViewModel classes and use Automapper to map them from the EF classes.
When you are updating records in the database though, you can control which fields in the ViewModel are used to update the existing fields in the EF class.
The normal process would be:
Use the Id to get the latest version of the existing object out of the database.
If you are using optimistic concurrency control then check that the object has not been updated since the ViewModel was created (so check timestamp for example).
Update this object with the required fields from your ViewModel object.
Persist the updated object back to the database.
Update to include Automapper examples:
Let's say your POCO is
public class MyObject
{
public int Id {get;set;}
public string Field1 {get;set;}
public string Field2 {get;set;}
}
and Field1 is the field you don't want updating.
You should declare a view model with the same properties:
public class MyObjectModel
{
public int Id {get;set;}
public string Field1 {get;set;}
public string Field2 {get;set;}
}
and Automap between them in the constructor of your Controller.
Mapper.CreateMap<MyObject, MyObjectModel>();
you can if you wish (although I prefer to do this manually, automap the other way too:
Mapper.CreateMap<MyObjectModel, MyObject>().ForMember(dest=>dest.Field1, opt=>opt.Ignore());
When you are sending date to your website you would use:
var myObjectModelInstance = Mapper.Map<MyObject, MyObjectModel>(myObjectInstance);
to create the viewModel.
When saving the data, you'd probably want something like:
public JsonResult SaveMyObject(MyObjectModel myModel)
{
var poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
if(myModel.Id == 0 )
{
//New object
poco.Field1 = myModel.Field1 //set Field1 for new creates only
}
}
although I'd probably remove the exclusion of Field1 above and do something like:
public JsonResult SaveMyObject(MyObjectModel myModel)
{
var poco;
if(myModel.Id == 0)
{
poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
}
else
{
poco = myDataLayer.GetMyObjectById(myModel.Id);
poco.Field2 = myModel.Field2;
}
myDataLayer.SaveMyObject(poco);
}
note I believe that best-practise would have you never Automap FROM the ViewModel, but to always do this manually, including for new items.
I just asked a very similar question, and I believe the answer to that one may help out a lot of folks who stumble across this one as well. The OP mentions that these are fields that should never change, and using PropertySaveBehavior.Ignore ensures this. With the existing answers to this question, you need to make custom save methods or introduce mapping where it might not make sense. By setting the AfterSave property behavior instead, you can prevent this from being possible in EF altogether.
In my project, I am generically accessing a property that is on an abstract class so I have to set it like this:
MyProperty.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
If you're accessing it directly on a known class, you'd use this:
...
.Property(e => e.YourProperty)
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);

Use T4 DBContext Script to Write Display Name Attribute

My issue is simple: the code I'm writing is in English, but the interface is in Portuguese. Not a problem, as I can do this:
[Display (Name = "Símbolo")]
public string Symbol { get; set; }
This way, when I render my screen, it comes in Portuguese:
#Html.LabelFor(model => model.Symbol)
But...
As I am using Model First EF for my project, classes are constantly been changed by a T4 DbContext Generator. That way I can't use Display attribute, as it will be overwrited.
A solution given here is to extend partial classes automatically created. Kinda clumsy for me.
So my idea is to change the T4 script to get Documentation.Summary attribute from the EDMX model and add it as a Display Name attribute.
I found an article where someone explains how to extract this data, but I'm not succeding in making it work on DbContext Generator.
Has someone ever made this? Do you guys have better ideas?
Thanks!

MEF: metadata seem to override interface when using GetExports

I'm building a MEF-based plugin-centric WPF application and I'm facing an issue with GetExports, maybe it's just my ignorance but I find an odd behaviour. I have a number of exported parts, all derived from 2 different interfaces (let's name them A and B), but all marked with the same metadata attribute X. So I have code like:
[Export(typeof(A))]
[TheXAttributeHere...]
public class SomePart1 : A { ... }
for each part, and the same for classes implementing B:
[Export(typeof(B))]
[TheXAttributeHere...]
public class SomePart2 : B { ... }
Now, when I try getting all the parts implementing A and decorated by attribute X with some values, MEF returns not only the A-implementing parts, but ALSO the B-implementing parts. So, when I expect to deal with A-objects I get a B, whence a cast exception.
In the real world, interfaces are named IItemPartEditorViewModel and IItemPartEditorView, while their common attribute is named ItemPartEditorAttribute and exposes a PartType string property on which I do some filtering. My code to get parts is thus like e.g.:
var p = (from l in container.GetExports<IItemPartEditorViewModel, IItemPartEditorMetadata>()
where l.Metadata.PartType == sPartType
select l).FirstOrDefault();
When looking for IItemPartEditorViewModel whose PartType is equal to some value, I get the IItemPartEditorView instead of IItemPartEditorViewModel implementing object. If I comment out the attribute in the IItemPartEditorView object instead, I correctly get the IItemPartEditorViewModel implementing object.
Update the suggested "templated" method was used, but I mistyped it here as I forgot to change lessthan and greaterthan into entities. Anyway, reviewing the code I noticed that in the attribute I had "ViewModel" instead or "View" for the interface type, so this was the problem. Shame on me, sorry for bothering :)!
I think I'd need to see more of the code to know for sure what's going on. However, I'd suggest you call GetExports like this:
// Get exports of type A
container.GetExports<A>();
// Get exports of type B
container.GetExports<B>();
Then do your filtering on the list returned. This will probably fix the cast issues you are having. I'd also be interested in seeing the code for the custom metadata attribute. If it derives from ExportAttribute for example, that might be part of the problem.

Odd problem with ListBox.DataSource

I'm writing a Windows application and using a Listbox control. I'm developing with Visual Studio C# 2008 Express Edition.
I've got a data object that looks something like this
public class RootObject
{
public List<SubObject> MySubObjects{ get; set;}
}
I've got a ListBox on my form, and also a property "MyRootObject" which, obviously, holds a RootObject. When the control is initialized, I set:
_listBox.DataSource = MyRootObject.MySubObjects;
Now, when the form loads, I debug and see that the DataSource is being set correctly. But nothing is displayed. I've overridden SubObject's ToString() method and it's not even being called. I tried setting _listBox.DisplayMember to a property of SubObject just to see if there was some problem there, but still nothing. I tried calling _listBox.Update() and _listBox.Refresh() after setting the DataSource, but still no love. The DataSource has all the data... it's just refusing to display it.
So while debugging, I wondered WTF and I decided to just do
_listBox.DataSource = new List<SubObject>{ new SubObject(), new SubObject() };
Sure enough, this worked, and I see two things listed in my listbox.
So then, really curious, I decided to try copying the list of objects and putting that in the listbox, like so:
_listBox.DataSource = MyRootObject.MySubObjects.ToArray();
This works! And it's a workaround to my problem for now... but a very annoying one. Does anyone know why I need to basically copy the list of objects like this to get it to work, rather than just setting the _listBox.DataSource = MyRootObject.MySubObjects; ? Again, the DataSource has all the right data either way after setting it... it's just when it's copied data, it actually displays, and when it's not, it's not displayed.
((CurrencyManager)_listBox.BindingContext[_listBox.DataSource]).Refresh();
Sux0r I know, but this works.
(originally found answer here)
Off the top of my head, this is because the ListBox.DataSource property must contain something that implements the IList interface. Your generic List<SubObject> does not implement IList; it implements IList<T> (in the System.Collections.Generic namespace). Array objects, on the other hand do inherit from IList, so handing the data in via that kind of object works.
You could try pulling an Enumerator (which also implements IList) out of your List<SubObject> object and plug that in. If it works, then the issue I've described is your problem. If it doesn't, then I'm talking out of my hat.
If this is indeed the issue, I am surprised that shoving in an unsupported object doesn't throw an exception.
so far that i know, whenever you want to set a collection to a
[ComboBox,ListBox].DataSource
you have to set the DisplayMember and ValueMember. DisplayMember and ValueMember are filled with the property name of the Class in the collection that is assigned to the listbox/combobox. Ex.
//Populate the data
RootObject root = new RootObject();
root.MySubObjects.Add(new SubObject("1", "data 1"));
root.MySubObjects.Add(new SubObject("2", "data 2"));
//Assign data to the data source
_listBox.DisplayMember = "DisplayProperty";
_listBox.ValueMember = "ValueProperty";
_listBox.DataSource = root.MySubObjects;
root.MySubObjects returns List of SubObject, and SubObject has to have properties called DisplayProperty and ValueProperty, ex.
public class RootObject
{
public List<SubObject> MySubObjects { get; set; }
}
public class SubObject
{
public string ValueProperty { get; set; }
public string DisplayProperty { get; set; }
}
I think you have to call Bind method after assigning to the list box data source
something like _listBox.DataSource.bind()
and you will have your listbox disappeared
you could try and use a BindingSource
( http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx )
inbetween the Listbox and your collection. Bindingsources handles a bunch of stuff and also includes Suspend/ResumeBinding properies that can be useful when updating the list
you could also try out wpf as its databinding is far superior to that of winforms :) but maybe thats not possible in your case
I believe you need to call _listbox.DataBind(); after assigning the datasource.
However, I've never used a property as a datasource before, I've only used methods. Have you tried changing your property to a method to see if that's the problem?
You could try
_listBox.DataSource = new BindingList<SubObject> (MyRootObject.MySubObjects);
instead. BindingList implements some more interfaces than List, which are essential for DataBinding.
I have a special rule for problems like this that I always try to remember before wasting an entire day hammering on it (believe me, I've spent many days hammering!). The rule is: when system behavior is really strange, the underlying cause must be very stupid. As intelligent programmers, we have a tendancy to search for esoteric causes or bugs in framework code to explain our problems. Sometimes the answer is that we were in a hurry and made a careless mistake that we haven't yet caught.
To quote Sherlock Holmes, "when you've removed the impossible, then whatever remains, no matter how improbable, must be the truth". In this case, the improbable truth is that the MySubObjects property of MyRoot object is null.