I am using Entity Framework 3.5. I have created an object that calls "Persons" that is inherited from SQL Membership table (aspnet_Users), they are linked by UserId (Guid) with 1-to-(0..1) relationship and they both belong to "UserSet".
Say, I have an existing "aspnet_User" called "jsmith" in the membership database already. How can I create just the "Person" (child) that links it to "jsmith" in entity framework?
Guid guid = new Guid("xxxx-xxxx-xxx..") // jsmith Guid
User user = GetUserByGuid(guid); // Assuming a function gets "jsmith" as "User"
// Try 1:
Person person = new Person();
person.UserId = guid;
context.AddToUserSet(person);
context.SaveChanges(); // This doesn't work and throws an error
// Try 2:
Person.CreatePerson(person); // Doesn't work either, because it creates a whole new user
context.SaveChanges(); // Throws an error
I even tried to create an EntityKey and use detach/attach, didn't work either. Am I doing anything wrong? Any help is appreciated.
R.B.
You should not put SQL membership into your entity model. ASP.NET membership is intended to be pluggable; you can swap out the SQL membership provider for, say, an OpenID or domain authentication provider. Mapping the SQL membership tables makes you totally dependent on the specific implementation of one version of that provider, which is bad coupling.
Also, even if you did do this, inheritance is the wrong relationship. A user has an account. A user is not an account. So the correct relationship is composition, not inheritance.
Perhaps "Person" is the wrong relationship in the example. However, if you are talking about extending ASP.NET memembership by adding more properties like "FirstName", "LastName", etc.. this is not totally wrong. There are some articles talk about extending SQL membership and/or creating "Custom Membership" by adding your own db table and then inherited from base MembershipUser class. In that case, it is inheritance.
There are some articles that talks about extending membership, but not on Entity though:
http://www.code-magazine.com/Article.aspx?quickid=0703071
More articles
- codesmart.wordpress.com/2009/03/27/extending-the-microsoft-aspnet-membership-provider/
Also, you may want to consider using Profiles as alternative.
Related
I have the following entities (pocos using Entity Framework 5):
Company: Id, Name, Applications, etc.
Application: Id, Name, etc.
There's a many-to-many relationship between companies and applications.
Having a company (without the apllications relationship loaded from the database) and a collection of application ids, I would like to clear the applications from the company and add the applications with ids specified in the collection.
I can attach applications using their ids, without loading them from the database, like this:
foreach (int id in selectedApplications)
{
Application application = new Application() { Id = id };
_context.Applications.Attach(application);
company.Applications.Add(application);
}
_context.SaveChanges();
But I need to clear the applications relationship first. Is there any way to clear a many-to-many relationship without loading it from the database first?
This is only way. company.Applications must be loaded when you add or remove items from it, otherwise the change tracker will never be aware of any changes.
Also, the junction table is not an entity in the conceptual model, so there is no way to set primitive foreign key properties as is possible in foreign key associations. You have to access the associations by the object collections.
I'm fairly new to EF and STE's, but I've stumbled on a painful point recently, and I'm wondering how others are dealing with it...
For example, suppose I have two STE's: Employee and Project. It's a many-to-many relationship. Each entity has a navigation property to the other (i.e. Employee.Projects and Project.Employees).
In my UI, a user can create/edit an Employee and associate it with multiple Projects. When the user is ready to commit, a list of Employees is passed to the server to save. However, if an Employee is not added to the "save list" (i.e. it was discarded), but an association was made to one or more Projects, the ApplyChanges extension method is able to "resurrect" the Employee object because it was "connected" to the object graph via the association to a Project.
My "save" code looks something like this:
public void UpdateEmployees(IEnumerable<Entities.Employee> employees)
{
using (var context = new EmployeeModelContainer(_connectionString))
{
foreach (var employee in employees)
{
context.Employees.ApplyChanges(employee);
}
context.SaveChanges();
}
}
I've been able to avoid this issue to now on other object graphs by using FKs to manipulate associations as described here: http://blogs.msdn.com/b/diego/archive/2010/10/06/self-tracking-entities-applychanges-and-duplicate-entities.aspx
How does one handle this when a many-to-many association and navigation properties are involved?
Thanks.
While this answer's a year late, perhaps it will be of some help to you (or at least someone else)
The simple answer is this: do not allow Entity Framework to infer m:m relationships. Unfortunately, I'm not aware of a way of preventing this, only how to deal with it after the fact.
By default, if I have a schema like this:
Employee EmployeeProject Project
----------- --------------- ----------
EmployeeId ---> EmployeeId |--> ProjectId
Name ProjectId ----- Name
... ...
Entity Framework will see that my EmployeeProject table is a simple association table with no additional information (for example, I might add a Date field to indicate when they joined a project). In such cases, it maps the relationship over an association rather than an entity. This makes for pretty code, as it helps to mitigate the oft-referenced impedence mismatch between a RDBMS and object-oriented development. After all, if I were just modeling these as objects, I'd code it the same way, right?
As you've seen, however, this can cause problems (even without using STE's, which cause even MORE problems with m:m relationships). So, what's a dev to do?
(The following assumes a DATABASE FIRST approach. Anything else and you're on your own)
You have two choices:
Add another column to your association table so that EF thinks it has more meaning and can't map it to an association. This is, of course, bad design, as you presumably don't need that column (otherwise you'd already have it) and you're only adding it because of the particular peculiarities of the ORM you've chosen. So don't.
After your context has been generated, map the association table yourself to an entity that you create by hand. To do that, follow the following steps:
Select the association in the designer and delete it. The designer will inform you that the table in question is no longer mapped and will ask you if you want to remove it from the model. Answer NO
Create a new entity (don't have it create a key property) and map it to your association table in the Mapping Details window
Right-click on your new entity and add an association
Correct the entity and multiplicity values (left side should have your association entity with a multiplicity of *, right should have the other entity with a multiplicity of 1)
Check the option that says "Add foreign key properties to the Entity"
Repeat for the other entity in the association
Fix the property names on the association entity (if desired...not strictly necessary but they're almost certainly wrong) and map them to the appropriate columns in the Mapping Details window
Select all of the scalar properties on your association entity and set them as EntityKey=True in the Properties window
Done!
I was wondering with Entity Framework 4.1 code first how do you guys handle queries that involve an existing aspnet_Users table?
Basically I have a requirement for a query that involves the aspnet_Users so that I can return the username:
SELECT t.Prop1, u.Username
FROM Table1 t
INNER JOIN aspnet_User u ON t.UserId = u.UserId
Where t.Prop2 = true
Ideally in linq I would like:
from t in context.Table1
join u in context.aspnet_Users on t.UserId equals u.UserId
where t.Prop2 = true
But I'm not sure how to get aspnet_Users mapping to a class User? how do I make aspnet_Users part of my dbset ?
Any help would be appreciated, thanks in advance
Don't map aspnet_Users table or any other table related to aspnet. These tables have their own data access and their own logic for accessing. Mapping these tables will introduce code duplication, possible problems and breaks separation of concerns. If you need users for queries, create view with only needed information like id, user name, email and map the view. The point is that view will be read only, it will contain only allowed data and your application will not accidentally modify these data without using ASP.NET API.
First read Ladislav's answer. If you still want to go ahead : to do what you want would involve mapping the users and roles and members tables into the codefirst domain - which means writing a membership provider in code-first.
Luckily there is a project for that http://codefirstmembership.codeplex.com/ although its not a perfect implementation. The original is VB, look in the Discussion tab for my work on getting it running in c# MVC.
I'm working with the author on a better implementation that protects the membership data (password, last logged on date, all of the non-allowed data) but allow you to map and extend the user table. But its not ready yet!
You don't really need to use Entity Framework to access aspnet_membership provider accounts. You really just need to create an instance of the membership object, pass in a unique user identifier and a Boolean value indicating whether to update the LastActivityDate value for the user and the method returns a MembershipUser object populated with current values from the data source for the specified user.
You can then access the username by using the property of "Username".
Example:
private MembershipUser user =
Membership.GetUser(7578ec40-9e91-4458-b3d6-0a69dee82c6e, True);
Response.Write(user.UserName);
In case you have additional questions about MembershipProvider, you can read up on it on the MSDN website under the title of "Managing Users by Using Membership".
Hope this helps you some with your requirement.
I am an experienced .NET developer but new to EF - so please bear with me. I will use an example of a college application to illustrate my problem. I have these user roles:
Lecturer, Student, Administrator.
In my code I envisage working with these entities as distinct classes so e.g. a Lecturer teaches a collection of Students. And work with 'is Student' 'TypeOf' etc.
Each of these entities share lots of common properties/methods e.g. they can all log onto the system and do stuff related to their role.
In EF designer I can create a base entity Person (or User...) and have Lecturer, Student and Administrator all inherit from that.
The difficulty I have is that a Lecturer can be an Administrator - and in fact on occasion a Student can be a Lecturer.
If I were to add other entities such as Employee and Warden then this gets even more of an issue.
I could presumably work with Interfaces so a person could implement ILecturer and IStudent, however I do not see how this fits within EF.
I would like to work within the EF designer if possible and I'm working model-first (coding in C#).
So any help and advice/samples would be very welcome and much appreciated.
Thanks
Don't make Student and Lecturer inherit from Person. As you say, what if "Bob" was both a student and a lecturer? This happens all the time in real colleges. You said it best yourself: These are roles, not types. A person can have many roles.
As a rule of thumb, avoid inheritance in O/R mapping when it's not strictly necessary (which is almost never). Just as when coding, favor composition over inheritance.
So you could give each Person a property Roles which is a 0..* collection of Roles. Then to get a list of students, you can do:
var students = from p in Context.People
where p.Roles.Any(r => r.Id = studentRoleId)
select p;
Or you could have a related Student type with a 0..1 relationship between Person and Student; this would allow you to add additional data for the student, e.g.:
var students = from p in Context.People
where p.StudentInfo != null
select new
{
Id = p.Id,
Name = p.Name,
Grades = p.Student.Grades
};
I have 2 entities: User and Company, with a FK from the User to the Company.
I'm trying to remove the association and leave the user entity with a scalar property "CompanyId", but still have the "Company" entity in the model (mainly to increase performance, I don't need to full entity attached to it).
I'm able to achieve that only by removing the association and then go to the edmx (xml) file and remove the leftovers manually, BUT...
After I regenerate the model (following additional changes in the schema etc.), I'm getting the "Company" association once again on the "User" object (along with the "CompanyId" property), which of course causes errors of mappings, since I'm having 2 mappings to the same CompanyId field in the database. Going once again to the xml to fix it is not something I'd like to do...
Is there a way around this? -Taking the "Company" table out to another model is not possible.
Thanks,
Nir.
I think I found the answer.
I can leave the entity association without the scalar property, and set it to a private getter. Then, add to the partial class the following:
public int CompanyId
{
get
{
return
(int)CompanyReference.EntityKey.EntityKeyValues.First(c => c.Key == "Id").Value;
}
}
That way I don't need to go to the database to fetch the company association along with the user, but I still have the value.
Nir.