I have a database first project and the context/entities are automatically generated with Scaffold-DbContext.
One table (Region_User) in the database is a cross reference table between User and Region, it contains only two fields UserId, and RegionId that together is the composit key for the table.
I'm currently trying to add a new Region_User to a user like below:
var userregions = new List<Region_User>();
userregions.Add(new Region_User { UserId = 1, RegionId = 1 });
user.Region_User = userregions;
and then try to save it to the database I get an error like:
{"Entity type 'Region_User' is defined with a 2-part composite key, but 1 values were passed to the 'DbSet.Find' method."}
The generated entity Region_User only contains the fields UserId and RegionId..
How should I do to save a new row in the Region_User table?
Related
I have issues by connecting to tables
I have 2 Model
First Model called PodioBorgerNotat with columns in the table called podio_borger_notats
id
user_id
item_id
app_item_id
borger_item_id (foreign key) 🔐
medarbejder_item_id
status
The second Model called PodioBorgerStamark with columns in the table podio_borger_stamarks
id
item_id (local key) 🔑
app_item_id
status
initials
name
I want to make a connection between PodioBorgerNotat and PodioBorgerStamark
so this is what I do in PodioBorgerNotat Model
public function borger()
{
return $this->belongsTo(PodioBorgerStamark::class, 'borger_item_id', 'item_id');
}
Now I want to output the result by executing this output
$borgernotater = PodioBorgerNotat::orderBy('created_at', 'acs')->orderBy('id', 'desc')->with('PodioBorgerStamark')->paginate(10);
This wont work and i get this error messsage
Call to undefined relationship [PodioBorgerStamark] on model [App\PodioBorgerNotat].
Your relation name is borger:
public function borger(){
...
}
You should call borger in with():
$borgernotater = PodioBorgerNotat
::orderBy('created_at', 'acs')
->orderBy('id', 'desc')
->with('borger')
->paginate(10);
I want insert record on database by EF with Guid Id based on zero values (00000000-0000-0000-0000-000000000000). On my GetDefaultGuidUser() method I can generate this value with default(Guid) but when I want insert on database I receive exception.
Cannot insert the value NULL into column 'Id', table 'auth.Core.Users'; column does not allow nulls. UPDATE fails.
var user = new UserRepository().GetDefaultGuidUser();
_context.Users.Add(user);
_context.SaveChanges();
However, I can update database with SQL script like this:
UPDATE core.users SET Id = '00000000-0000-0000-0000-000000000000'
What's wrong?
Apparently, EF6 doesn't like objects that have multiple foreign key properties that use the same key value, but do not share the same reference. For example:
var user1 = new AppUser { Id = 1 };
var user2 = new AppUser { Id = 1 };
var address = new Address
{
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
};
When I attempt to insert this record, EF throws this exception:
Saving or accepting changes failed because more than one entity of type
'AppUser' have the same primary key value. [blah blah blah]
I've discovered that doing this resolves the issue:
var user1 = new AppUser { Id = 1 };
var user2 = user1; //same reference
I could write some helper code to normalize the references, but I'd rather EF just know they're the same object based on the ID alone.
As for why EF does this, one explanation could be that its trying to avoid doing multipe CRUD operations on the same object since separate instances of the same entity could contain different data. I'd like to be able to tell EF not to worry about that.
Update
So it's as I suspected per my last paragraph above. In absense of a means to tell EF not to do CRUD on either instance, I will just do this for now:
if (address.ModifiedBy.Id == address.CreatedBy.Id)
{
address.ModifiedBy = address.CreatedBy;
}
Works well enough so long as I am not trying to do CRUD on either.
Update2
I've previously resorted to doing this to prevent EF from validating otherwise-required null properties when all I need is the child entity's ID. However, it doesn't keep EF from going into a tizzy over separate instances with the same ID. If it's not going to do CRUD on either AppUser object, why does it care if the instances are different?
foreach (var o in new object[] { address.ModifiedBy, address.CreatedBy })
{
db.Entry(o).State = EntityState.Unchanged;
}
If you get AppUser from context, then you will not need to do anything, because Entity Framework will track entities:
var user1 = context.AppUsers.Find(1);
var user2 = context.AppUsers.Find(1);
var address = new Address
{
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
};
Now, they both will point to same objects and will not cause to conflict.
You can add two extra properties to have the Id for the main objects which is the AppUser, then you can use only one AppUser object and reference it for both the created and modified by properties.
CreatedById = user1.Id,
ModifiedById = user1.Id
Otherwise, your code will end up by saving two instances of AppUser with the same primary key.
Another approach is to set both the foreign key properties to only one AppUserobject
The explanation is that EF's change tracker is an identity map. I.e. a record in the database is mapped to one, and only one, CLR object.
This can be demonstrated easily by trying to attach two objects with the same key:
context.AppUsers.Attach(new AppUser { Id = 1 });
context.AppUsers.Attach(new AppUser { Id = 1 });
The second line will throw an exception:
Attaching an entity of type 'AppUser' failed because another entity of the same type already has the same primary key value.
This also happens if you assign
CreatedBy = user1, //different reference
ModifiedBy = user2 //different reference
Somewhere in the process, user1 and user2 must be attached to the context, giving rise to the exception you get.
Apparently, you have a function that receives two Id values that can be different or identical. Admittedly, it would be very convenient if you could simply create two AppUser instances from these Ids, not having to worry about identical keys. Unfortunately, your solution ...
if (address.ModifiedBy.Id == address.CreatedBy.Id)
... is necessary. Solid enough, though.
I have following structure in Oracle database:
Course(CourseId, Name)
->Student(StudentId, Name, Comment, CourseId)
->Subject(SubjectId, Name, SubjectComment, CourseId)
Student contains some of Primitive Properties (StudentId, Name, CourseId, Comment) and Navigation Property (Courses [Linked with DTO name Course on CourseId]).
Table structure is also same as Entity structure and currenly using Explicit loading to extract the data from Oracle database, using LoadProperty and Load.
I need to load the Collection and Object with selected property, as Load Student with StudentId and Name (without Comment column).
LoadProperty(Student, s => s.Courses), load only CourseId (don't load Name primitive property in Course DTO). So, Student.Courses.First().CourseId will be a value and Name will be null as intentionally excluded from loading from database.
LoadProperty(Course, c => c.Subjects) load only SubjectId without Name property, even don't go to database to load.
Is there any way to Include/Exclude the Primitive types to load?
Not with load property and not with entities. You must create custom query and use projection to load only selected columns:
var student = from s in context.Students
select new {
StudentId = s.StudentId,
... // Other student's properties
CourseId = s.Course.Id,
SubjectIds = s.Courese.Subjects.Select(s => s.Ids)
};
Say I have two entities with about 20 properties per entity and a Many-to-Many relationship like so:
User (Id int,Name string, .......)
Issue (Id int,Name string, .......)
IssueAssignment (UserId,RoleId)
I want to create a new Issue and assign it to a number of existing Users. If I have code like so:
foreach(var userId in existingUserIds)
{
int id = userId
var user = _db.Users.First(r => r.Id == id);
issue.AssignedUsers.add(user);
}
_db.Users.AddObject(user);
_db.SaveChanges();
I noticed it seems terrribly inefficient when I run it against my SQL Database. If I look at
the SQL Profiler it's doing the following:
SELECT TOP(1) * FROM User WHERE UserId = userId
SELECT * FROM IssueAssignment ON User.Id = userId
INSERT INTO User ....
INSERT INTO IssueAssignment
My questions are:
(a) why do (1) and (2) have to happen at all?
(b) Both (1) and (2) bring back all fields do I need to do a object projection to limit the
fields, seems like unnecessary work too.
Thanks for the help
I have some possible clues for you:
This is how EF behaves. _db.Users is actaully a query and calling First on the query means executing the query in database.
I guess you are using EFv4 with T4 template and lazy loading is turned on. T4 templates create 'clever' objects which are able to fixup their navigation properties so once you add a User to an Issue it internally triggers fixup and tries to add the Issue to the User as well. This in turns triggers lazy loading of all issues related to the user.
So the trick is using dummy objects instead of real user. You know the id and you only want to create realtion between new issue and existing user. Try this (works with EFv4+ and POCOs):
foreach(var userId in existingUserIds)
{
var user = new User { Id = userId };
var _db.Users.Attach(user); // User with this Id mustn't be already loaded
issue.AssignedUsers.Add(user);
}
context.Issues.AddObject(issue);
context.SaveChanges();