Mapping a Dto to an object with id - c#

I am making an app using the ASP.Net Boilerplate framework and in my Domain layer I have a simple "Boss" entity. Creating and retrieving these entities from the database works fine but I can't get the "Update" to work. When map my "UpdateBossDto" to a Boss object and try to update it I get this error:
$exception {System.InvalidOperationException: The instance of entity
type 'Boss' cannot be tracked because another instance with the same
key value for {'Id'} is already being tracked. When attaching existing
entities, ensure that only one entity instance with a given key value
is attached. Consider using
'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the
conflicting key values.
This error gets thrown in the BossManager class (I have removed the other methods for readability.
public class BossManager : DomainService, IBossManager
{
private readonly IRepository<Boss> _repositoryBoss;
public BossManager(IRepository<Boss> repositoryBoss)
{
_repositoryBoss = repositoryBoss;
}
public void Update(Boss entity)
{
_repositoryBoss.UpdateAsync(entity);
}
}
Here is my Update method in the BossAppService (i know getting the Id this way probably isn't great but right now I'm just desperate):
public void Update(UpdateBossDto updatedBoss)
{
var boss = new Boss();
updatedBoss.Id = _bossManager.GetBossIdByName(updatedBoss.Name);
boss = ObjectMapper.Map<Boss>(updatedBoss);
_bossManager.Update(boss);
}
And my UpdateDto class which holds the same attributes as the Boss class itself:
public class UpdateBossDto
{
public int Id { get; set; }
public string Name { get; set; }
public int Hp { get; set; }
public int CombatLvl { get; set; }
public int MaxHit { get; set; }
public string AttackStyle { get; set; }
public string Weakness { get; set; }
public string ImageUrl { get; set; }
}
How can I update the Boss object either with or without the Id? Any help would be greatly appreciated!

There's a number of issues here. First, the id should be coming from the request URL, since it uniquely identifies the resource that's being modified. This also saves you from having to do silly things like GetBossIdByName. Not only does that require an unnecessary query, but it's prone to error. The id is your key for a reason: it's unique. Names are not. You could have multiple bosses with the same name. Additionally, your name columns are likely not indexed, which means such a query is vastly more inefficient. Then, with your id, you should be querying the corresponding Boss out of your database, and mapping onto this instance, not creating a new instance. Finally, save that same instance back to the database. Then, you will have no issues.

Related

How to create 0..1-1 relationship in EF6

I have a problem trying to correctly configure a relationship in EF. I have used EF code first to generate classes from an existing database. The first table holds a list of instructions, the second holds a record of the state that each instruction is in.
Tables (simplified):
Instruction
-----------
InstructionID
CurrentInstructionStateHistoryID
InstructionStateHistory
-----------------------
InstructionStateHistoryID
InstructionID
State
So you can see that there are two relationships between the tables - a 1-many relationship based on InstructionID, which I'm not interested in, and have therefore deleted the properties for. The second relationship is based on the CurrentInstructionStateHistoryID property, which points to the "current" state of the instruction.
The classes are as follows:
public partial class Instruction
{
[Key]
public int InstructionID { get; set; }
public int? CurrentInstructionStateHistoryID { get; set; }
public virtual CurrentInstructionStateHistory InstructionStateHistory { get; set; }
}
public partial class InstructionStateHistory
{
[Key]
public int InstructionStateHistoryID { get; set; }
public int InstructionID { get; set; }
public string State { get; set; }
public virtual Instruction tblInstruction { get; set; }
}
Here's the fluent API setup to define the relationship:
modelBuilder.Entity<InstructionStateHistory>()
.HasRequired(e => e.tblInstruction)
.WithOptional(e => e.CurrentInstructionStateHistory);
So, it all compiles and runs. But when I get to a bit of code like this:
Instruction instruction = await _dal.InstructionRepository.Find(claimID);
InstructionStateHistory history = i.CurrentInstructionStateHistory;
I can see that the instruction is populated correctly, let's say the Id is 1234. When I examine the InstructionStateHistory object, what I want to see is that it's InstructionID is 1234, but instead what I see is that it's InstructionStateHistoryID, i.e. is's primary key, is 1234 and that it's related to a completely different instruction.
Somehow I need to tell EF that Instruction.CurrentInstructionStateHistoryID links to InstructionStateHistory.InstructionStateHistoryID.
I've tried many combinations of data annotations and fluent setup but have been unable to find a combination that actually works, either I get the above result or a runtime error. Any help gratefully accepted!
It seems like EF just can't handle this case, so the solution was to forget the concept of a "current" InstructionStateHistory. Instead I added a date field to the InstructionStateHistory table, and then changed the Instruction class to have a regular collection property as follows:
public virtual ICollection<InstructionStateHistory> InstructionStateHistories{ get; set; }
Then when I need the "current" state I just query the colection, sort by date and take the latest one.

Entity framework 6 foreign key is not being updated on attach and save

I have a issue with entity framework 6 not updating the foreign key when I try to update a entity object. It works on insert (but then I have to set the state to Unchanged for not to reinsert a new entity in the foreign key table). I am using code first approach and generated the models myself. It's a web application so the entity objects gets detached, so I have to reattach them.
I've created a simplified example so it's easy to explain what my problem is. In this example I have a car object which has a one to many relation to make. I want to update a car and change what make it is and its name. The name is updated but not the foreign key value. How do I go ahead to get the foreign key to be updated too?
The code handeling the attaching
public void UpdateCars(Car car){
var dbContext = new CarsDbContext(); //Inherits DbContext
dbContext.Cars.Attach(car);
dbContext.Entry(car).State = EntityState.Modified;
dbContext.SaveChanges();
}
The car Entity
[Table("Car")]
public class Car
{
public Guid Id { get; set; }
public String Name { get; set; }
public virtual Make Make { get; set; }
}
[Table("Make")]
public class Make
{
public Guid Id { get; set; }
public String Name { get; set; }
}
Edit:
I did a few more changes with help from comments (thanks guys!) and I made something work but it feels like I'm doing it the wrong way because the code is far from pretty. Here's what I did:
Modified the Car object to:
public String Name { get; set; }
public Guid Make_Id
[ForeignKey("Make_Id")]
public virtual Make Make { get; set; }
In my update
var dbContext = new CarsDbContext(); //Inherits DbContext
car.Make_Id = car.Make.Id;
dbContext.Cars.Attach(car);
There surely must be a better practice around this when doing EF code first when working with detached entities?
I ended up using graphdiff which solved all my problems. Also when my entities became more complex and it tried to attachs same entity several times. Here's a article to read about it: http://blog.brentmckendrick.com/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/

Fluent Nhibernate save persisted entity twice in database

I have a base class with ID as Primary Key and 3 version numbers.
[NotNull]
public virtual int Id { get; private set; }
[NotNull]
[NotUpdatable]
public virtual int BaseVersion { get; set; }
[NotNull]
[NotUpdatable]
public virtual int MajorVersion { get; set; }
[NotNull]
[NotUpdatable]
public virtual int MinorVersion { get; set; }
Now I want to persist the object again if it gets a new version number or if it does not exist in the database.
foreach (var dataObject in unitOfWork.NewObjects)
{
if (dataObject.Id > 0)
{
_transactionHelper.GetSession().SaveOrUpdate(dataObject.DeepClone());
continue;
}
_transactionHelper.GetSession().SaveOrUpdate(dataObject);
}
My idea was to make a deepclone but sadly (for me) Nhibernate only updates the existing datarecord. I got some succes with
_transactionHelper.GetSession().Evict(dataObject);
_transactionHelper.GetSession().Save(dataObject.DeepClone());
But then Nhibernate Cascading features does not working properly and I get some times this exception detached entity passed to persist (what is correct).
Some Ideas? Or do i have to progamm is by myself :/
Thanks!
I solved this problem by writing my own mapping container which tracks the state of a relation. I think the main problem was/is that I used my own composite tables (I needed to add some values like active).
To persist an allready persisted entity I used:
_transactionHelper.GetSession().Evict(dataObject);
dataObject.Id = 0;
_transactionHelper.GetSession().Save(dataObject);
It looks like this solution works very well for my problem.

Easier way of avoiding duplicates in entity framework

Can anyone provide an easier more automatic way of doing this?
I have the following save method for a FilterComboTemplate model. The data has been converted from json to a c# model entity by the webapi.
So I don't create duplicate entries in the DeviceProperty table I have to go through each filter in turn and retrieve the assigned DeviceFilterProperty from the context and override the object in the filter. See the code below.
I have all the object Id's if they already exist so it seems like this should be handled automatically but perhaps that's just wishful thinking.
public void Save(FilterComboTemplate comboTemplate)
{
// Set the Device Properties so we don't create dupes
foreach (var filter in comboTemplate.Filters)
{
filter.DeviceProperty = context.DeviceFilterProperties.Find(filter.DeviceFilterProperty.DeviceFilterPropertyId);
}
context.FilterComboTemplates.Add(comboTemplate);
context.SaveChanges();
}
From here I'm going to have to check whether any of the filters exist too and then manually update them if they are different to what's in the database so as not to keep creating a whole new set after an edit of a FilterComboTemplate.
I'm finding myself writing a lot of this type of code. I've included the other model classes below for a bit of context.
public class FilterComboTemplate
{
public FilterComboTemplate()
{
Filters = new Collection<Filter>();
}
[Key]
public int FilterComboTemplateId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public ICollection<Filter> Filters { get; set; }
}
public class Filter
{
[Key]
public int FilterId { get; set; }
[Required]
public DeviceFilterProperty DeviceFilterProperty { get; set; }
[Required]
public bool Exclude { get; set; }
[Required]
public string Data1 { get; set; }
}
public class DeviceFilterProperty
{
[Key]
public int DeviceFilterPropertyId { get; set; }
[Required]
public string Name { get; set; }
}
Judging from some similar questions on SO, it does not seem something EF does automatically...
It's probably not a massive cut on code but you could do something like this, an extension method on DbContext (or on your particular dataContext):
public static bool Exists<TEntity>(this MyDataContext context, int id)
{
// your code here, something similar to
return context.Set<TEntity>().Any(x => x.Id == id);
// or with reflection:
return context.Set<TEntity>().Any(x => {
var props = typeof(TEntity).GetProperties();
var myProp = props.First(y => y.GetCustomAttributes(typeof(Key), true).length > 0)
var objectId = myProp.GetValue(x)
return objectId == id;
});
}
This will check if an object with that key exists in the DbContext. Naturally a similar method can be created to actually return that entity as well.
There are two "returns" in the code, just use the one you prefer. The former will force you to have all entities inherit from an "Entity" object with an Id Property (which is not necessarily a bad thing, but I can see the pain in this... you will also need to force the TEntity param: where TEntity : Entity or similar).
Take the "reflection" solution with a pinch of salt, first of all the performance may be a problem, second of all I don't have VS running up now, so I don't even know if it compiles ok, let alone work!
Let me know if that works :)
It seems that you have some common operations for parameters after it's bound from request.
You may consider to write custom parameter bindings to reuse the code. HongMei's blog is a good start point: http://blogs.msdn.com/b/hongmeig1/archive/2012/09/28/how-to-customize-parameter-binding.aspx
You may use the code in Scenario 2 to get the formatter binding to deserialize the model from body and perform the operations your want after that.
See the final step in the blog to specify the parameter type you want customize.

How change tracking works in Entity Framework

Given the following code, how does EF/DbContext knows about the change made to the customer object:
class Program
{
static void Main()
{
using(var shopContext = new ShopContext())
{
var customer = shopContext.Customers.Find(7);
customer.City = "Marion";
customer.State = "Indiana";
shopContext.SaveChanges();
}
}
}
public class ShopContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string State { get; set; }
}
Thank you
When you load the entity from the context it keeps an additional data structure - let's call it entry. The entry contains two set of values - original values and current values. When you execute the SaveChanges operation EF goes through your customer entities and updates current values in the entry so that they match with the real state of your entity - this operation is called detecting changes. During SQL command generation EF will compare current and original values and build an SQL update statement to modify changed values in the database. This operation is called snapshot change tracking - EF keeps a snap shot in the entry.
There is an alternative called dynamic change tracking which will modify the current value in the entry at the same time you assign the value to your entity's property. Dynamic change tracking has specific requirements (like all of your properties in the entity must be virtual) because it must wrap your class to a dynamic proxy at runtime. This used to be the preferred way but due to some performance issues in complex scenarios, snapshot change tracking is currently supposed to be used as default.

Categories