I have a table defined in my Entity model. I also have the foreign key Navigation properties defined on the tables in the model.
Users
- UserID
- Username
- UserGroupID
Groups
- GroupID
- GroupName
I have a grid connected to an EntityDataSource, which retrieves and displays the Users table. Instead of displaying the UserGroupID identity column for each user, I need to display the corresponding GroupName. Is there an easy built in way to grab the GroupName from the User object since they are connected in the entity model?
Thanks!
Kevin
In this tutorial, the GridView that displays the Instructors table does what you are trying to do with EntityDataSource and GridView (display a value from a navigation property):
http://www.asp.net/web-forms/tutorials/getting-started-with-ef/the-entity-framework-and-aspnet-getting-started-part-4
You should setup an association on each entity. For Code First it should look something like this:
class User {
// user properties...
[ForeignKey("UserGroupID")]
public virtual Group Group { get; set; }
}
class Group {
// group properties...
public virtual ICollection<User> Users { get;set; }
}
Then you can just call:
user.Group.GroupName
Related
I am using MVC 5 with Entity Framework 6 and Unit of Work pattern.
Tables: and fields
Customer - Id, Name
ContactType - Id, Name (Home contact, work contact etc)
ContactDetails - Id, CustomerId, ContactTypeId, ContactValue
One Customer can have multiple Contact Details (so Customer1 has a home contact, work contact etc).
The ContactType table is a look-up table so it just displays the types of contacts available (home, work, emergency, mobile etc)
I have created the Interfaces and Classes as required to carry out the basic Add, Edit functionality, then created an Unit Of Work class to hold all these Repositories.
Tested it out and everything works as expected when i hard code values in.
When i created my MVC application, i added the below lines to add this entry into a database using the Unit of Work class
public ActionResult SaveContactDetails(CustomerContactType viewModel)
{
_unitOfWork.Customers.Add(viewModel.Customer);
_unitOfWork.ContactDetails.Add(viewModel.ContactDetail);
//_unitOfWork.SaveAllChanges();
return View();
}
I created a new ViewModel called CustomerContactType which is a class containing the tables i require in order to save the data successfully
public class CustomerContactType
{
public ContactType ContactType { get; set; }
public IEnumerable<ContactType> ContactTypes { get; set; }
public Customer Customer { get; set; }
public ContactDetail ContactDetail { get; set; }
}
I realised how to assign a dropdown value to the model within the .cshtml, so the ContactDetails table knows which ContactType is associated with that contact number (Home, emergency etc).
The problem i have is the ContactDetails requires a customer ID. This customer ID doesnt generate until the customer is saved so im not sure how i should be doing this?
These two lines carry out the task but i can see the customerID is null in the second line where i would have preferred it to contain the ID
_unitOfWork.Customers.Add(viewModel.Customer);
_unitOfWork.ContactDetails.Add(viewModel.ContactDetail);
I can provide additional code if required but wasnt sure if theres an easy fix or not.
Instead of using CustomerId in ContactDetails, why not change CustomerId to be of a complex type Customer and decorate it with a foreign key attribute? That way you can add a ContactDetails object along with a Customer object assigned to its property and a single call to SaveChanges should persist both entities to the DB.
I realize this has been answered more than once, here for example, but nothing seems to be working for me and I'm not sure why.
My database has Sites and Users. A User might own a Site, or he might work at a Site. He might own Sites A and C, but work on Site B. However, each site has only one worker and one owner. Therefore, I have created a join table structure with the following three tables: User, Site, and User_Site, and User_Site contains a column called role that can be either "worker" or "owner".
To simplify things, I have created two views, view_Worker and view_Owner. view_Owner, for example, is
SELECT User_Site.site_id, User.*
FROM User_Site
JOIN User ON User_Site.user_id = User.user_id
WHERE User_Site.role = "owner"
Therefore, each row in view_Owner contains all of the information on User and the site_id for which the User is joined as an "owner".
Now, I'm trying to build an API around this database using Entity Framework 6. I've gotten a number of errors trying a number of different things, so I'm not sure which errors to post here. I'll post my most recent error:
dbContext.cs
public DbSet<User> Users { get; set; }
public DbSet<Site> Sites { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Site>()
.HasOptional<User>(s => s.Owner)
.WithMany()
.Map(m =>
{
m.MapKey("site_id").ToTable("view_Owner");
});
}
user.cs
[Table("User")]
public class User
{
[Key, Column("user_id")]
public int ID { get; set; }
}
site.cs
[Table("Site")]
public class Site
{
[Key, Column("site_id")]
public int ID { get; set; }
public virtual User Owner { get; set; }
}
The error message I get with this configuration is
The specified table 'view_Owner' was not found in the model. Ensure
that the table name has been correctly specified.
So, the next step is to try and add this table to the model. I change [Table("User")] to [Table("view_Owner")] and I get the following error message:
(66,6) : error 3021: Problem in mapping fragments starting at line
66:Each of the following columns in table User is mapped to multiple
conceptual side properties: User.site_id is mapped to
(66,6) : error 3025: Problem in mapping fragments starting at line
66:Must specify mapping for all key properties (User.user_id) of table
User.
Clarification
Ideally, I'd like a way to simply tell EntityFramework to load the Owner property on Site from the view_Owner table by joining view_Owner.site_id to the Site.site_id primary key. But, since the Owner property is still of type User, it doesn't need a new definition.
i'm working on C# MVC 4 web app
i created a page linked to a DB and my question is that in the Create New record the user can enter the ID, Name, ...
how can i hide in the View from the user the ID and make it take an auto incremental number for example when the user goes to page Create New he will have to start filling the Name, Address ... without seeing the ID field which must take automatically the value of a number:
here is my model code:
public partial class Employee
{
public int Identifier { get; private set; }
public string Name { get; set; }
public string Address { get; set; }
public string Status { get; set; }
}
You should let the DB handle the Id incrementation. I would set the Id to private in case you need it for business operations. But you can remove it from the view.
Edit the view and remove the ID part from it, then it depends by how you designed the DB, if you have auto-increment in it, otherwise you should manage it in the controller.
Matteo
Use a AutoIncrement database field.
Here are some common ways to do that
If after your INSERT INTO statement you want to get the ID your database generated put
SELECT SCOPE_IDENTITY();
for SQL Server to return the ID it generated.
Usually you use a Guid to represent an ID. The reason for this is that you can not know the last ID of the last inserted entity (in your case Employee). To find it you you insert it into the database (let the db handle the increment) and the database server responds with the incremented ID.
To know the exact ID of the inserted entity use a Guid. The Guid is a very large integer that has a very small chance of being idendical to another inserted Guid. Thus you wont have to wait for the database to respond with the inserted ID.
Note you can not bast the Guid to an int. You have to change the field type.
Currently I am new to MVC and practicing with some demo applications.
I have 2 models.
Employee - (with data members employeeId,name,gender,city,deptId)
Department - (with data members id,name,Collection employees )
I have put these two classes inside a context class inheriting from DbContext.
Problem is when I try to get employee data based on deptId , it throws error that department_Id column is not defined. If I remove the employees data member from Department then everything works fine. What exactly is happening here, why is it automatically adding a column, and how to tackle it?
Don't add deptId property to your Employee class. Just add a navigation property like this:
public virtual Department Department { get; set; }
And your Department class:
public virtual ICollection<Employee> Employees { get; set; }
Then Entity Framework will create all necessary relationships automatically for you.
For more informatin about Navigation Properties take a look at here: http://msdn.microsoft.com/en-us/data/jj713564.aspx
A little curiosity. I have a User object which contains a bag each of UserPhoto, UserMatchInterest, UserPreference objects. I have given each item in the bag a reference to the parent User and with nhibernate I have got the two way mapping sorted so that when you Create the user object for the first time, it automatically creates the UserPhoto, UserMatchInterest and UserPreference objects in the collection bags, setting the UserId to the parent User object, that works fine.
As an example, the UserPhoto table has a PhotoId PK column and a UserId FK column. The UserPhoto object has the PhotoId property and a User property (not UserId) and so rather than holding the UserId, it holds a reference to the parent and populates the DB column based on the Users PK.
The problem I have is when I want to update the User object all in one go. The rest of the User object updates fine, but when it comes to the photos, it creates new photos in the database. I can understand why, as they are not linked at all to the previous photo session objects which is acceptable as being an ASP.NET website I will be dealing with detached objects. But it leaves the old ones. So if you had photo ID 1 & 2, with UserId=1. After the update, you will have photos 1,2,3 & 4 with UserId=1. What I want is for photo 1 & 2 to be deleted and then insert 3 & 4 instead.
I have tried to retrieve them independently as a collection and delete them in the transaction first, but I get the message
Message = "deleted object would be re-saved by cascade (remove deleted object from associations)
Code to delete is as follows
// First delete existing photos, interests and preferences
var photos = from row in repository.GetItemsAsQuery<UserPhoto>()
where row.User.UserId == user.UserId
select row;
repository.DeleteItems(photos.ToList());
var interests = from row in repository.GetItemsAsQuery<UserMatchInterest>()
where row.User.UserId == user.UserId
select row;
repository.DeleteItems(interests.ToList());
var preferences = from row in repository.GetItemsAsQuery<UserPreference>()
where row.User.UserId == user.UserId
select row;
repository.DeleteItems(preferences.ToList());
// Now update the user object and re-add the above linked items
repository.UpdateItem(user);
The error is thrown on the repository.DeleteItems(interests.ToList()); line, the first delete passes fine - though it is all in a transaction.
My question is am I approaching this the right way to update an object in the DB which has bags of other objects it needs to update as well? I don't see any way to update existing photo objects without manually setting ID's - and the user may have replaced all photos or added/deleted anyway so it is probably cleaner to delete existing and re-add new, but how do I delete existing ones without getting this cascade error?
from your description i envision the following classes
public class User
{
public virtual int Id { get; set; }
public virtual ICollection<Photo> Photos { get; private set; }
}
public class Photo
{
public User Parent { get; set; }
public virtual string Name { get; set; }
public virtual byte[] Data { get; set; }
}
then the mapping would look like
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id);
HasMany(x => x.Photos)
.AsSet() // no duplicate entries, allows NH to optimise some things
.Cascade.AllDeleteOrphan()
.Component(c =>
{
c.ParentReference(x => x.Parent);
c.Map(x => x.Name);
c.Map(x => x.Data);
});
}
}
Note: the Cascade.AllDeleteOrphan will delete all children automaticly which are not part of the collection anymore