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.
Related
I'm implementing a POCO in my project that represents a row in my database table. I'd like to modify one of the values in the constructor.
Unfortunately, it seems that the values are populated only after the constructor is run, so there's no way for me to perform my required logic. Is this a bug or by design?
I should probably mention that I'm using Code First.
public partial class CheckpointValue
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("saljare")]
public int SalesAgentId { get; set; }
[Column("volym")]
public int Value { get; set; }
[Column("datum")]
public DateTime Date { get; set; }
[Column("typ")]
public string Type { get; set; }
public CheckpointValue()
{
// Values empty... Why haven't they been populated when the constructor is run?
}
}
Unfortunately, it seems that the values are populated only after the
constructor is run, so there's no way for me to perform my required
logic. Is this a bug or by design?
This is by design. BTW, how you would be able to get these properties already populated during construction-time without providing constructor arguments?.
Maybe you're trying to implement your logic in the wrong place. If you're looking for implementing business rules, domain validation or who knows what, it should be done in another class. For example, your repository would be a good place to do things before returning the requested object.
public CheckpointValue GetById(Guid id)
{
CheckpointValue checkpointValue = YourDbContext.CheckpointValues.Find(id);
// Implement here what you wanted in your class constructor...
return checkpointValue;
}
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.
My domain class:
public class Address
{
[Key]
public virtual string AddressId { get; set; }
public virtual string Address { get; set; }
}
In my MVC controller I want to check the given Address exist, before I insert.
public ActionResult Create(Address address)
{
if (ModelState.IsValid)
{
if (db.Addresses.Any(a => a.AddressId == address.AddressId)) // how I do it now
{
ModelState.AddModelError(string.Empty, "Address Id already exists!");
}
else
{
db.Addresses.Add(address);
db.SaveChanges();
return RedirectToAction("Index");
}
}
}
But there are lot of other domain classes in my project and I want to do the same check again and again.
My question is I want to write a generic method in my Db context class to perform this check. (looks like below or similar)
public bool Exists(object) {
// return true if exist
}
i.e. a method which I can call like this:
db.Exists(address)
Thanks!
You could use generics and do something like the following:
public class YourDbContext : DbContext
{
...
public bool Exists<TEntity>(object id)
where TEntity : class
{
var dbSet = Set<TEntity>();
var entity = dbSet.Find(id);
return entity != null;
}
Which you'd then use like:
db.Exists<Address>(address.AddressId);
Using Find isn't the most efficient way to handle this, but it has the key benefit that you're not required to know what the actual primary key property on the class is, which would greatly complicate this method. For example, Address has AddressId, but Foo might have FooId.
UPDATE
Since ultimately this just uses Find under the hood, you just have to modify the method slightly to be able to take multiple parameters. Find handles composite keys by allowing one more parameters to be passed to it. But bear in mind, the the order matters and must align with the key order you specified when configuring your entity.
public bool Exists<TEntity>(params object[] keys)
where TEntity : class
{
var dbSet = Set<TEntity>();
var entity = dbSet.Find(keys);
return entity != null;
}
I've got an object that has a property which, on creation, should always be populated with the object's id(primary key).
How do I do that?
I've tried assigning the id to the field just after the db savechanges(), before returning to the view, but that creates two records on my db.
Also tried loading a new instance of the same, assign the id to the field and save it, but also creates two records.
Thanks for any help.
//model
public partial class supplier
{
public int id { get; set; }
public int ref { get; set; }
}
//controller
public ActionResult Create(supplier sup)
{
if (ModelState.IsValid)
{
db.suppliers.add(sup)
db.SaveChanges();
sup.ref = sup.id;
db.SaveChanges();
}
...
}
Hi all, thanks for all your help... I've found a solution... don't really know if it's the correct one, but it does the job.
For whoever is interested here it is:
supplier needToUpdateSupplier = (from s in db.suppliers where s.id.Equals(supplier.id) select s).ToList().FirstOrDefault();
if (needToUpdateSupplier != null)
{
needToUpdateSupplier.ref = supplier.id;
db.suppliers.Attach(needToUpdateSupplier);
db.Entry(needToUpdateSupplier).Property(e => e.ref).IsModified = true;
db.SaveChanges();
}
Create the object
Save it (SaveChanges). This will give you the id.
Assign the id to your property, using the existing object (you don't need to load it again)
Save again
Notes: The property must be nullable, because up on creation it will be empty.
// A Test object
class MyObject
{
public int ID {set;get;}
public int? MyProperty {set;get;}
}
void Foo()
{
var test = new MyObject();
db.MyObjects.Add(test);
db.SaveChanges();
// at this moment test has the Id set. You can assign it.
test.MyProperty = test.Id;
db.SaveChanges();
}
With EF it should set the ID for you:
db.Posts.Add(post);
db.SaveChanges();
// post.ID should be now set
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.