Reputation: 4264
I'm looking to find a good design for accomplishing the following.
In our C# MVC project using entity frameworks (and codefirst) we have, for sake of this conversation, 3 tables. Resource, Profile, Organization.
When we add a Profile record, we first need to create a Resource record, and using the ResourceId as the ProfileId. The same for adding an Organization.
I'm not sure if there is a good way to handle this. Right now we do something like this:
public IHttpActionResult PostProfile(Profile profile)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var res = new Resource();
_db.Resource.Add(res);
_db.SaveChanges();
profile.ProfileId = res.ResourceId;
_db.Profile.Add(profile);
_db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = profile.ProfileId }, profile);
}
Is there a better way?
Upvotes: 0
Views: 792
Reputation: 2989
Your code is not atomic what happens if the second SaveChanges crashes for example because database doesn't respond,...
It's better to take a approach with just one SaveChanges()
var res = new Resource();
_db.Resource.Add(res);
profile.ProfileId = res.ResourceId;
_db.Profile.Add(profile);
_db.SaveChanges();
A part from this I think that is better to model objects in a different way, instead of having the ID of Resource in Profile, have the entire object, and the you can get advantage of lazy loading, a more powerful queries.
public class Resource()
{
public int ID { get; set; }
.......
}
public class Profile()
{
public int ID { get; set; }
.....
public virtual Resource Resource { get; set; }
}
And the code to add the new item
var profile = new Profile()
{
Resource = new Resource(),
....
}
_db.Profile.Add(profile);
_db.SaveChanges();
Upvotes: 1
Reputation: 191
If your Profile
class needs the ResourceId
, you may add a new property:
public class Profile
{
public int Id { get; set; }
public int ResourceId { get; set; }
public virtual Resource Resource { get; set; }
...
}
The virtual
keyword is to manage change tracking and lazy loading.
In your db context OnModelCreating()
method link both fields:
modelBuilder.Entity<Profile>().HasRequired(x => x.Profile)
.WithMany().HasForeignKey(x => x.ProfileId);
Instead on HasRequired()
use HasOptional()
, if required. More on this topic can be found at MSDN - Configuring Relationships with the Fluent API.
Now you can add both objects in a single db operation:
var _profile = new Profile();
// set more _profile properties
_profile.Resource = new Resource
{
// set resource properties, but
// exclude the Id property
};
_db.Profile.Add(_profile);
_db.SaveChanges();
Upvotes: 0