Property Is Required on Update EF6 - c#

I have a property that is required on my entity. Upon adding the entity to the database, that property is populated by the system. From here on, this property should never be changed. This property is also never passed to the client.
So now when the user edits this entity, and it is passed to my service layer, the property is null. Is it possible to tell EF that this property should not be modified and never updated, or is my only option, to retrieve the value from the database and populate the edited entity with the same value before SaveChangesAsync is called?
Here is an example of my entity
public myEntity() {
public long Id { get; set; }
public string Name { get; set; }
public string SystemProperty { get; set; }
}
Only the properties Id and Name are passed to the client. When AddAsync is calling in my service, i populate SystemProperty myself.
Here is my UpdateAsync, which is making DbContext throw an exception of
SystemProperty is required
public override Task<int> UpdateAsync(Module updated)
{
_context.Modules.Attach(updated);
// do not update
_context.SetModified(updated, "SystemProperty", false);
return _context.SaveChangesAsync();
}
My SetModified method has been created against my DbContext so i can unit test the method.
public void SetModified(object entity, string property, bool isModified)
{
this.Entry(entity).Property(property).IsModified = isModified;
}
As you can see, i thought i could use the IsModified = false, but that doesnt seem to ignore the property.
What are my options?

Best workaround I know:
entity.Property = "placeholder";
var entry = _context.Entry(entity);
entry.State = EntryState.Modified;
entry.Property(m => m.Property).IsModified = false;
_context.SaveChanges();
You mark entity as modified and then exclude not modified properties. As for validation, you need to set valid value for that field just to pass validation.

Related

Creating model with default fields

I Have this Vehicle Model and I want to have some default values for my field when I first create the object and add it to the database. The problem is that this constructor is being called several times, not just in the creation of the Vehicle object.
What am I doing wrong? Should I use another method to create models with default fields?
public class Vehicle
{
[Key]
public int VehicleId { get; set; }
public bool Validated { get; set; }
public DateTime CreationTime { get; set; }
public Vehicle()
{
this.CreationTime = DateTime.Now;
this.Validated = false;
}
}
Edit: Every time I call db.Vehicles.Find(id); it seems to me that Vehicle constructor is called, which is not what I want. I only want constructor to be called the first time object is created in the system, before being inserted to the database
// GET: Vehicles/Edit/5
public ActionResult Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Vehicle vehicle = db.Vehicles.Find(id);
if (vehicle == null)
{
return HttpNotFound();
}
return View(vehicle);
}
If you want to control the initialisation then you could do something like this:
var myVehicle = new Vehicle
{
CreationTime = DateTime.Now,
Validated = false,
};
The default constructor (either the auto-generated one, or one you have written), will always be called, but if it does 'nothing', then when EF creates one, it will not impact anything.
Your update seems to imply you don't want the constructor to get invoked, which I don't think you'll be able to avoid.
When EF Core creates instances of these types, such as for the results
of a query, it will first call the default parameterless constructor
and then set each property to the value from the database. However, if
EF Core finds a parameterized constructor with parameter names and
types that match those of mapped properties, then it will instead call
the parameterized constructor with values for those properties and
will not set each property explicitly.

Partially updating an entity in EF6

I'm trying to figure out how to smoothly do a partial update (basically a HTTP PATCH) of an entity, using Entity Framework 6.0, but I'm stumped at the number of examples out there that don't seem to work for me (even those that aren't obviously for another version of EF).
What I'd like to accomplish:
The entity is updated without having to load it first; i.e. there's only one trip to the database
Only the properties that I touch are updated - others are left as is
The closest I've gotten is neatly described by this answer to a very similar question, and illustrated by the following code:
public async Task UpdateMyEntity(int id, int? updatedProperty, string otherProperty)
{
using (var context = new MyDbContext())
{
var entity = new MyEntity { Id = id };
context.MyEntities.Attach(entity);
if (updatedProperty != null) { entity.Property = updatedProperty.Value; }
if (!string.IsNullOrEmpty(otherProperty) { entity.OtherProperty = otherProperty; }
await context.SaveChangesAsync();
}
}
Now, this works for simple entities, but I'm getting entity validation errors because I have a couple of required properties and relations that are not updated and therefore not present in the attached entity. As noted, I'd just like to ignore those.
I've debugged and verified that context.Entry(entity).Property(e => e.Property).IsModified changes to true when that line is run, and that all the properties I never touch still return false for similar checks, so I thought EF would be able to handle this.
Is it possible to resolve this under the two constraints above? How?
Update:
With LSU.Net's answer I understand somewhat what I have to do, but it doesn't work fully. The logic fails for referential properties.
Consider the following domain model:
public class MyEntity
{
public int Id { get; set; }
public int Property { get; set; }
[Required]
public string OtherProperty { get; set; }
[Required]
public OtherEntity Related { get; set; }
}
public class OtherEntity
{
public int Id { get; set; }
public string SomeProperty { get; set; }
}
Now, if I try to update a MyEntity, I do the following:
var entity = new MyEntity { Id = 123 }; // an entity with this id exists in db
context.MyEntities.Attach(entity);
if (updatedProperty != null) { entity.Property = updatedProperty.Value; }
await context.SaveChangesAsync();
In my custom validation method, overridden as in the answer below, the validation error on the required property OtherProperty is correctly removed, since it is not modified. However, I still get a validation error on the Related property, because entityEntry.Member("Related") is DbReferenceEntry, not DbPropertyEntry, and thus the validation error is not marked as a false error.
I tried adding a separate, analogous clause for handling reference properties, but the entityEntry doesn't seem to mark those as changed; with relation = member as DbReferenceEntry, relation doesn't have anything to indicate that the relationship is changed.
What can I check against for false errors in this case? Are there any other cases I need to handle specially (one-to-many relationships, for example)?
Entity Framework validation with partial updates
#Shimmy has written some code here to omit the validation logic for unmodified properties. That may work for you.
protected override DbEntityValidationResult ValidateEntity(
DbEntityEntry entityEntry,
IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
var falseErrors = result.ValidationErrors
.Where(error =>
{
var member = entityEntry.Member(error.PropertyName);
var property = member as DbPropertyEntry;
if (property != null)
return !property.IsModified;
else
return false;//not false err;
});
foreach (var error in falseErrors.ToArray())
result.ValidationErrors.Remove(error);
return result;
}

Using db context and binded object in the same action of a controller. How to Update the db?

I didn't find any relevant answer here so I will trigger you, thanks in advance :
I have a controller with 2 methods of the Edit action, (I simplified it for better understanding):
MrSaleBeta01.Controllers
{
public class PostsController : Controller
{
private MrSaleDB db = new MrSaleDB();
...
// GET: Posts/Edit/5
public ActionResult Edit(int? id)
{
...
}
// POST: Posts/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit( Post post, int? CategoryIdLevel1, int? CategoryIdLevel2, int? originalCategoryId)
{
...
Category cnew = db.Categories.Find(post.CategoryId);
MoveFromCategory(post, originalCategoryId);
...
db.Entry(post).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
//move post from his old category (fromCategoryId) to a new one (post.CategoryId):
//returns true on success, false on failure.
public bool MoveFromCategory(Post post, int? fromCategoryId)
{
try
{
if (post.CategoryId == fromCategoryId)
return true;
Category cold = null, cnew = null;
if (fromCategoryId!=null)
cold = db.Categories.Find(fromCategoryId);
if (post.CategoryId != 0)
cnew = db.Categories.Find(post.CategoryId);
if (cold != null)
{
cold.Posts.Remove(post);
}
if( cnew != null)
cnew.Posts.Add(post);
db.Entry(cold).State = EntityState.Modified;
db.Entry(cnew).State = EntityState.Modified;
//db.Entry(p).State = EntityState.Modified;
//db.SaveChanges();
return true;
}
catch (Exception)
{
return false;
//throw;
}
}
}
}
So, the idea is very default: The first method is called by Get and returns the View of Edit. Then I need to save the changes by sending the post object from the view to the HttpPost Edit method.
My Model is something like that (I simplified it for better understanding):
MrSaleBeta01.Models
{
public class Post
{
public int Id { get; set; }
[ForeignKey("Category")]
public virtual int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public Category()
{
this.Categories = new List<Category>();
this.Posts = new List<Post>();
}
#region Primitive Properties
public int CategoryId { get; set; }
public string Name { get; set; }
#endregion
#region Navigation Properties
public virtual IList<Post> Posts { get; set; }
#endregion
}
}
The idea: Every Post needs to have it's Category. Every Category can have multiple Posts or none. (1-N relationship).
The problem:
In the Edit (HttpPost) method, after I update the Category's objects (move the Post from it's category to a different category object. After that I do some other modifications on post object), I get an error in the line of the edit method:
db.Entry(post).State = EntityState.Modified;
saying that:
{"Attaching an entity of type 'MrSaleBeta01.Models.Post' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate."}
The error is beacuse there is a conflict to the line:
cold.Posts.Remove(post);
And even to the line:
cnew.Posts.Add(post);
I tried to use the solution of AsNoTracking() but without success,
I also tried to change the line "db.Entry(post).State = EntityState.Modified" line to:
db.As.Attach(post)
but that line is even cannot be compiled.
What am I doing wrong? How can I solve that issue?
1) You dont have to call .Attach() nor .State = anything.
You have your Entity created as proxy object (cold = db.Categories.Find(fromCategoryId);), its proxy responsibility to track any changes. As exception say, this COULD be your problem.
2) public int CategoryId { get; set; } should be marked with [Key] (i am not sure if convention mark it as primary key, but i doubt it - i think EF conventions take this PK as FK to Category, which could confuse object graph and behave strangely...)
3) Uh, just noticed... Why are you using your FromCategory method at all? I may overlook something, but looks like it just remove Category from collection and add it to another... EF proxy does this automatically for you, right after post.CategoryId = newCatId;
Edit1:
4) Change public virtual IList<Post> Posts { get; set; } to public virtual ICollection<Post> Posts { get; set; }
Edit2:
1) that was created automatically while I scaffold the PostsController according to the Post model. So I guess I need it?
3) It's not just remove Category from collection and add it to another, but remove the post from the collection of posts in one category to another. So I don't think that EF proxy does this automatically.
I am not famillier with ASP, i work with desktop MVP/MVVM, so i am not sure here - but from my point of view, you really dont need to touch EntityState as long as you are using var x = db.Set<X>().Create(); (== db.X.Create();) (NOT var x = new X();) for new entities and db.Set<X>().FetchMeWhatever(); (== db.X.FetchMeWhatever();) for everything else (Otherwise you get only POCO without proxy. From your example, it looks like you are doing it right ;) ).
Then you have entity with proxy (thats why you have your reference properties on model virtual - this new emitted proxy type override them) and this proxy will take care for 1:n, m:n, 1:1 relations for you. I think this is why folks are using mappers (not only EF and not only DB mappers) mainly :) For me it looks like, you are trying to do this manually and it is unnecessary and its just making a mess.
Proxy also take care of change tracking (so as i say, you dont need to set EntityState manually, only in extreme cases - I can not think of any right now... Even with concurrency.)
So my advice is:
Use only ICollection<> for referencing collections
Check and get rid of any var entity = new Entity(); (as i say, looks like you are doing this)
Throw away every db.Entry(x).State = EntityState.whatever; (trust EF and his change tracker)
Set only one side of reference - it doesnt matter if Category.Posts or Post.Category or even Post.CategoryId - and let mapper do the work. Please note that this will work only with proxy types (as i say above) on entities with virtual referencing & id & ICollection<> properties.
Btw, there are 2 types of change tracking, snippet and proxy - snippet have original values in RAM and is comparing them at SaveChanges() time, for proxy tracking, you need to have all your properties marked virtual - and comparing them at x.Prop = "x" time. But thats off-topic ;)

Mapping a DTO to an Entity with Automapper

I have an Entity Framework POCO with the following structure.
public class Entity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
I've created a Data Transfer Object for this entity to be used by my views.
public class EntityDto
{
public int Id { get; set; }
public string Name { get; set; }
}
Now, I have the following mapping code in my Global.asax file.
Mapper.CreateMap<Entity, EntityDto>();
Mapper.CreateMap<EntityDto, Entity>(); // not sure whether I need this as well?
Everything is working fine, I pass the DTO to my views OK and I can create a new instance of Entity from my EntityDto model. The problem arises when I try to edit my Entity; I'm aware this is down to AutoMapper losing the Entity Key that EF creates to track changes to the object, but having read through a few sources there doesn't seem to be a definitive solution. Here is the action I'm using to edit my entity.
public ActionResult EditEntity(EntityDto model)
{
var entity = context.Entities.Single(e => e.Id == model.Id);
entity = Mapper.Map<EntityDto, Entity>(model); // this loses the Entity Key stuff
context.SaveChanges();
return View(model);
}
Now, what do I do to solve this? Can I:
Somehow tell AutoMapper to .Ignore() the Entity Key properties?
Get AutoMapper to copy out the Entity Key properties?
.Attach() my mapped Entity and set the state to modified?
Any help always appreciated.
Try passing entity as a second parameter to your mapping.
entity = Mapper.Map<EntityDto, Entity>(model, entity);
Otherwise, your entity instance is overwritten with a new instance, and you lose the entity created in the first line.
.Attach() my mapped Entity and set the state to modified?
public ActionResult EditEntity(EntityDto model)
{
var entity = Mapper.Map<Entity>(model);
context.Set<Entity>().Attach(entity); // (or context.Entity.Attach(entity);)
context.Entry<Entity>(entity).State = System.Data.EntityState.Modified;
context.SaveChanges();
return View(model);
}
Where is your context instantiated? You should do that in your EditEntity action imo.
public ActionResult EditEntity(EntityDto model)
{
using(var context = new MyContext())
{
var entity = Mapper.Map<Entity>(model);
context.Set<Entity>().Attach(entity); // (or context.Entity.Attach(entity);)
context.Entry<Entity>(entity).State = System.Data.EntityState.Modified;
context.SaveChanges();
return View(model);
}
}
An alternative answer that doesn't require Automapper for the DTO to Entity conversion is using a DbEntry:
var oldEntity = DbSet.FirstOrDefault(x => x.Id == updatedEntity.Id);
var oldEntry = Context.Entry(oldEntity);
oldEntry.CurrentValues.SetValues(updatedEntity);
You don't need any attach/state checking because you are getting the old entity first so it has change tracking attached to it. Also, the CurrentValues.SetValues can accept a different type, in this example updatedEntity is the DTO. Set Values documentation is explained as such:
Sets the values of this dictionary by reading values out of the given object. The given object can be of any type. Any property on the object with a name that matches a property name in the dictionary and can be read will be read. Other properties will be ignored. This allows, for example, copying of properties from simple Data Transfer Objects (DTOs).
So seems like it already can perform in an automapper-esque way.

How can I add default values to a property when saving using Code First EF4.1?

I started by creating some models like this:
public abstract class EditableBase
{
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public int CreatedBy { get; set; }
public int ModifiedBy { get; set; }
}
public class Project : EditableBase
{
public int ProjectId { get; set; }
public string ProjectName { get; set; }
}
And I use this line when the app starts:
Database.SetInitializer<ModelContext>(
new DropCreateDatabaseIfModelChanges<ModelContext>());
A table called Projects is created with all the properties mentioned above as columns... this is exactly what I wanted.
However, now I need populate some default values when I issue a SaveChanges() on DbContext. When I save I need to update the ModifiedOn and ModifiedBy properties with the appropriate values.
Normally I would at least do the DateTime values on the database side (either a trigger or a stored procedure) however this is obviously not an option here since the database will be dropped anytime a class changes. And since I did code first I do not have a model designer that I can tweak the properties on.
What I would like to do is add a method in the EditableBase class that gets called when the SaveChanges() is executed, thus keeping all the logic involved in one place. Is it possible to do this? What is the best way to achieve my goal?
Override SaveChanges in your derived DbContext:
public override int SaveChanges()
{
foreach(var entry in ChangeTracker.Entries<EditableBase>())
{
var entity = entry.Entity;
if (entry.State == EntityState.Added)
{
entity.CreatedOn = ...;
entity.CreatedBy = ...;
}
else if (entry.State == EntityState.Modified)
{
entity.ModifiedOn = ...;
entity.ModifiedBy = ...;
}
}
return base.SaveChanges();
}
I'm only not sure if generic Entries will work directly with your base type becasue it is not actually mapped as base entity. There is also non generic version so you can rewrite it to more complex linq query or test each entry's entity type in loop.
Well, you have complete control over the code for your entities. I'd imagine you would probably want to implement an IPropertyChanged like pattern to update your properties.
Did consider the two options in this post where you do something on the setter (or constructor)?
The default attribute solution seems a good one.

Categories

Resources