using Navigation property to get Data - c#

I am creating App using Entity Framework.I have loaded the Database model from Database.here In the Course table Department is the Navigation Property,DepartmentID is the foreign key.I have created a gridview and set its Datasource to Course Table,but I want to see the Deaptment Name instead of department ID.I can use the Navigation properties like Department.count but how can I use the navigation property to get data (Department name) from Department Table.
Any one who can help me with this
THIS IS MY CODE
var result = (from o in ctx.Courses.Include("Department")
where o.Title == TextBox2.Text
select o
).First();
//GridView4.DataSourceID="";
GridView3.DataSource=result;
GridView3.DataBind();
If I dont use the First Function then i can't access the Department Name attribute,If i use the First() It say that
Data source is an invalid type. It must be either an IListSource, IEnumerable, or IDataSource.
please tell me how i can solve it?

I think Products and Categories tables in Northwind are similar than your need. I would write a query like this:
var ctx = new NorthwindEntities();
var query = from prod in ctx.Products
where prod.ProductName.StartsWith("C")
select new { prod.ProductName, prod.UnitPrice, prod.Category.CategoryName };

var result = (from c in dbContext.Course
select c).First();
if(!result.Department.IsLoaded)
{
result.Department.Load(); //this will load the course.Department navigation property
}
//Assuming you have 1 - 1 relationship with course to department
string departmentName = result.Department.Name;
or if you have 1 - M relationship with the department then:
foreach(Department d in result.Department)
{
Console.WriteLine(d.Name);
}
EDIT:
Instead of trying to load Department do the following
if(!result.DepartmentReference.IsLoaded)
{
result.DepartmentReference.Load()
}
How to: Explicitly Load Related Objects

Related

When selecting new Type - The entity or complex type cannot be constructed in a LINQ to Entities query

When I call this linq query I get the following error:
The entity or complex type 'DataModel.CustomerContact' cannot be constructed in a LINQ to Entities query.
I don't understand what I am doing wrong here. Normally when I am not joining with any other tables and have no navigation properties I would typically just select cc, but in this case I need to create a new CustomerContact object so I can bind the navigation properties.
I did some research on this and is there really no way to do this? If I use an anonymous type how do I convert to to a CustomerContact since I need to ultimately return a list of CustomerContact to my application? If I simply select cc then cc.CustomerName will not get set. I am really trying to avoid creating Dtos when I should just be able to use the auto-generated EF object classes.
public static IEnumerable<CustomerContacts> GetList(int customerId = null)
{
using (var context = new AppContext())
{
var cList = (from cc in context.CustomerContacts
join c in context.Customers on cc.CustomerId equals c.Id
where (customerId == null || cc.CustomerId == customerId)
select new CustomerContact
{
Id = cc.Id,
FirstName = cc.FirstName,
LastName = cc.LastName,
Email = cc.Email,
// navigation properties
CustomerName = c.Name
}).ToList();
return objList;
}
}
If I simply select cc then cc.CustomerName will not get set
You could do:
from cc in context.CustomerContacts.Include(cc => cc.CustomerName)
...to get the navigation property loaded automatically for you. Search for "EF navigation properties lazy loading".
Note, you need to have 'using ...some namespace I can't remember' to get that syntax to work because it uses an extension method. Otherwise you can just quote the name of the navigation property you want to load, as in:
from cc in context.CustomerContacts.Include("CustomerName")

Return a List<T> based data from two or more tables in SQL Server

In sql server, I have two tables (lets say Person and School). I want to return the Person.Name from one table and School.Name (since they are related I want the primary key of the Person also).
So the question here is can I return these data and make them all in a list? also for the return type, does it request that I create a custom type for it (I mean class)?
Edit: Sorry I forget to metion that I need it in LINQ.
Thanks,
Maybe there is a better way to do this, but I would create a new class and return a list of these objects. Like this:
First do a LiNQ query to get the values we need:
var personWithSchoolName = select p from db.Person
select s from db.School
where p.SchoolId == s.SchoolId
select new { p.PersonId as PersonId, p.Name as PersonName, s.Name as SchoolName };
peopleWithSchoolNamesList = personWithSchoolName.ToList();
Then loop through the results and add these to a new list:
foreach(object o in peopleWithSchoolNamesList)
{
PersonWithSchoolNameObject personWithSchoolNameObject = new PersonWithSchoolNameObject(o.PersonId, o.PersonName, o.SchoolName);
ListWithPeople.Add(PersonWithSchoolNameObject);
}
return ListWithPeople;
You can use Join operation of LINQ to combine data from more than one table
For return purposes you will need a Concrete class. You cannot return the results of LINQ query i.e. an anonymous type, directly.
Try this
SELECT Person.Id, Person.Name, School.Name AS SchoolName
from Person
LEFT JOIN School ON Person.SchoolId = School.Id
(actually you have to use well prepared linq to return this, yeah?)
and wrap the results into special predefined class like:
class PersonWithSchool
{
public int PersonId;
public string PersonName;
public string SchoolName;
}

Adding a relationship without requerying the database

I know I've seen this but I cant find it anywhere.
I have a couple objects with a many-to-many relationship: Person and Department. A person can have many departments and vice versa.
I thought it was:
var person = //query user
var d = new Department();
d.Id = 123;
person.Departments.add(d);
This creates a new department in the database and links them but that isnt what I want. The department already exists. I just want to create the relationship. How can I do this without having to requery the database to get an instance of the department?
Try this:
var department = dbContext.Departments.FirstOrDefault(d => d.Id == 123);
person.Departments.Add(department);
dbContext.SaveChanges();
This shouldn't query the database until dbContext.SaveChanges() is called as deferred querying is used. However, if that doesn't work, you can try updating the mapping entity directly instead:
var departmentMember = new DepartmentMember
{
DepartmentId = 123,
MemberId = person.Id
};
dbContext.DepartmentMembers.Add(departmentMember);
dbContext.SaveChanges();
How about:
person.Departments.Add(context.Departments.First(c=>c.Id==123));

Entity Framework Does not Import Table with Super Key

I have 4 tables:
but when I create an entity framework model, why is tblRoleInProfile not generated?
I have a Linq TO SQL model that want to convert it to EF and now my table is not generated. How can I solve that?
UPDATE 1:
You consider we have some profiles and some roles. If we want Profile A has role 1 Insert a record in tblRoleInProperty and if we want Profile B has not Role 2 (If it exists) delete it's record from tblRoleInProperty. I don't want delete a profile. another problem is select new projection. Can any body guide me to write this query in EF:
var prs = from p in dc.tblProfiles
join rp in dc.tblRoleInProfiles
on p.ProfileId equals rp.ProfileId
join r in dc.tblRoles
on rp.RoleId equals r.RoleId
select new
{
ProfileName = p.ProfileName,
ProfileId = p.ProfileId,
RoleName = r.RoleName,
RoleId = r.RoleId
};
Thanks
This is how EF works. EF is ORM tool - it tries to hide persistance details and junction table in many-to-many relation is exactly that detail you don't want to see in your object model.
You can rewrite your query simply to:
var prs = from p in dc.tblProfiles
from r in p.tblRoles
select new
{
ProfileName = p.ProfileName,
ProfileId = p.ProfileId,
RoleName = r.RoleName,
RoleId = r.RoleId
};
Updating and deleting relations also works through navigation properties.
Inserting role to profile:
// Dummy objects so you do not need to load them from DB first.
// These objects must exist in database
var p = new Profile { ProfileId = ... };
var r = new Role { RoleId = ... };
context.tblProfiles.Attach(p);
context.tblRoles.Attach(r);
p.tblRoles.Add(r);
context.SaveChanges();
Deleting role from profile:
// Dummy objects so you do not need to load them from DB first.
// These objects must exist in database
var p = new Profile { ProfileId = ... };
var r = new Role { RoleId = ... };
p.tblRoles.Add(r);
context.tblProfiles.Attach(p);
context.tblRoles.Attach(r);
p.tblRoles.Remove(r);
// another approach:
// context.ObjectStateManager.ChangeRelationshipState(p, r, x => x.tblRoles, EntityState.Deleted);
context.SaveChanges();
but when I create an entity framework
model Why tblRoleInProfile not
generated?
Entity Framework correctly identified the table representing a pure many-to-many relationship between tblProfile and tblRole. This relationship is now expressed through the navigation properties in those two tables. When you access the navigation property, EF will do a join for you internally to return the right related entities to you - in the end this will lead to much cleaner queries since you don't need to express the join explicitly anymore.
As for your example I would reconsider the tbl prefix on your tables / entities - It really hurts readability.
You can change your table to hold an extra ID column instead of the superkey. I know it's not neccessary, but that way EF will definitely import it.
In general, you shouldn't do anything. Your entities are Role and Profile. You'd want to use the relationships created between the entities.
var db = new Entities(); //whatever your context name is
var r = new Role{RoleName="Rtest"};
var p = new Profile {ProfileName = "PTest"};
p.Roles.Add(r);
db.Profiles.AddObject(p);
db.SaveChanges();
EF will take care of the rest. I know you have work invested in L2S, but you may find your life easier if you follow the EF happy path and makes some changes instead of forcing EF to look like LINQ to SQL.
You can query like this:
var qu = from r in dc.tblRoles
where r.tblProfiles.Any(p=> p.ProfileId == 42)
select r;
foreach (var r in qu) {
Console.WriteLine(r.RoleName)
foreach (var p in r.tblProfiles) {
Console.WriteLine(p.ProfileName)
}
}
My Solution was to insert a column to the relationship table:
tblRoleInProfile (
ProfileId int not null,
RoleId int not null,
UpdateDate DateTime not null
)...
dont actually needed the column in my case, but it serves the purpose

Entity Framework with LINQ aggregate to concatenate string?

This is easy for me to perform in TSQL, but I'm just sitting here banging my head against the desk trying to get it to work in EF4!
I have a table, lets call it TestData. It has fields, say: DataTypeID, Name, DataValue.
DataTypeID, Name, DataValue
1,"Data 1","Value1"
1,"Data 1","Value2"
2,"Data 1","Value3"
3,"Data 1","Value4"
I want to group on DataID/Name, and concatenate DataValue into a CSV string. The desired result should contain -
DataTypeID, Name, DataValues
1,"Data 1","Value1,Value2"
2,"Data 1","Value3"
3,"Data 1","Value4"
Now, here's how I'm trying to do it -
var query = (from t in context.TestData
group h by new { DataTypeID = h.DataTypeID, Name = h.Name } into g
select new
{
DataTypeID = g.Key.DataTypeID,
Name = g.Key.Name,
DataValues = (string)g.Aggregate("", (a, b) => (a != "" ? "," : "") + b.DataValue),
}).ToList()
The problem is that LINQ to Entities does not know how to convert this into SQL. This is part of a union of 3 LINQ queries, and I'd really like it to keep it that way. I imagine that I could retrieve the data and then perform the aggregate later. For performance reasons, that wouldn't work for my app. I also considered using a SQL server function. But that just doesn't seem "right" in the EF4 world.
Anyone care to take a crack at this?
If the ToList() is part of your original query and not just added for this example, then use LINQ to Objects on the resulting list to do the aggregation:
var query = (from t in context.TestData
group t by new { DataTypeID = t.DataTypeID, Name = t.Name } into g
select new { DataTypeID = g.Key.DataTypeID, Name = g.Key.Name, Data = g.AsEnumerable()})
.ToList()
.Select (q => new { DataTypeID = q.DataTypeID, Name = q.Name, DataValues = q.Data.Aggregate ("", (acc, t) => (acc == "" ? "" : acc + ",") + t.DataValue) });
Tested in LINQPad and it produces this result:
Some of the Answers suggest calling ToList() and then perform the calculation as LINQ to OBJECT. That's fine for a little amount of data, but what if I have a huge amount of data that I do not want to load into memory too early, then, ToList() may not be an option.
So, the better idea would be to process/format the data in the presentation layer and let the Data Access layer do only loading or saving raw data that SQL likes.
Moreover, in your presentation layer, most probably you are filtering the data by paging, or maybe you are showing one row in the details page, so, the data you will load into the memory is likely smaller than the data you load from the database. (Your situation/architecture may be different,.. but I am saying, most likely).
I had a similar requirement. My problem was to get the list of items from the Entity Framework object and create a formatted string (comma separated value)
I created a property in my View Model which will hold the raw data from the repository and when populating that property, the LINQ query won't be a problem because you are simply querying what SQL understands.
Then, I created a get-only property in my ViewModel which reads that Raw entity property and formats the data before displaying.
public class MyViewModel
{
public IEnumerable<Entity> RawChildItems { get; set; }
public string FormattedData
{
get
{
if (this.RawChildItems == null)
return string.Empty;
string[] theItems = this.RawChildItems.ToArray();
return theItems.Length > 0
? string.Format("{0} ( {1} )", this.AnotherRegularProperty, String.Join(", ", theItems.Select(z => z.Substring(0, 1))))
: string.Empty;
}
}
}
Ok, in that way, I loaded the Data from LINQ to Entity to this View Model easily without calling.ToList().
Example:
IQueryable<MyEntity> myEntities = _myRepository.GetData();
IQueryable<MyViewModel> viewModels = myEntities.Select(x => new MyViewModel() { RawChildItems = x.MyChildren })
Now, I can call the FormattedData property of MyViewModel anytime when I need and the Getter will be executed only when the property is called, which is another benefit of this pattern (lazy processing).
An architecture recommendation: I strongly recommend to keep the data access layer away from all formatting or view logic or anything that SQL does not understand.
Your Entity Framework classes should be simple POCO that can directly map to a database column without any special mapper. And your Data Access layer (say a Repository that fetches data from your DbContext using LINQ to SQL) should get only the data that is directly stored in your database. No extra logic.
Then, you should have a dedicated set of classes for your Presentation Layer (say ViewModels) which will contain all logic for formatting data that your user likes to see. In that way, you won't have to struggle with the limitation of Entity Framework LINQ. I will never pass my Entity Framework model directly to the View. Nor, I will let my Data Access layer creates the ViewModel for me. Creating ViewModel can be delegated to your domain service layer or application layer, which is an upper layer than your Data Access Layer.
Thanks to moi_meme for the answer. What I was hoping to do is NOT POSSIBLE with LINQ to Entities. As others have suggested, you have to use LINQ to Objects to get access to string manipulation methods.
See the link posted by moi_meme for more info.
Update 8/27/2018 - Updated Link (again) - https://web.archive.org/web/20141106094131/http://www.mythos-rini.com/blog/archives/4510
And since I'm taking flack for a link-only answer from 8 years ago, I'll clarify just in case the archived copy disappears some day. The basic gist of it is that you cannot access string.join in EF queries. You must create the LINQ query, then call ToList() in order to execute the query against the db. Then you have the data in memory (aka LINQ to Objects), so you can access string.join.
The suggested code from the referenced link above is as follows -
var result1 = (from a in users
b in roles
where (a.RoleCollection.Any(x => x.RoleId = b.RoleId))
select new
{
UserName = a.UserName,
RoleNames = b.RoleName)
});
var result2 = (from a in result1.ToList()
group a by a.UserName into userGroup
select new
{
UserName = userGroup.FirstOrDefault().UserName,
RoleNames = String.Join(", ", (userGroup.Select(x => x.RoleNames)).ToArray())
});
The author further suggests replacing string.join with aggregate for better performance, like so -
RoleNames = (userGroup.Select(x => x.RoleNames)).Aggregate((a,b) => (a + ", " + b))
You are so very close already. Try this:
var query = (from t in context.TestData
group h by new { DataTypeID = h.DataTypeID, Name = h.Name } into g
select new
{
DataTypeID = g.Key.DataTypeID,
Name = g.Key.Name,
DataValues = String.Join(",", g),
}).ToList()
Alternatively, you could do this, if EF doesn't allow the String.Join (which Linq-to-SQL does):
var qs = (from t in context.TestData
group h by new { DataTypeID = h.DataTypeID, Name = h.Name } into g
select new
{
DataTypeID = g.Key.DataTypeID,
Name = g.Key.Name,
DataValues = g
}).ToArray();
var query = (from q in qs
select new
{
q.DataTypeID,
q.Name,
DataValues = String.Join(",", q.DataValues),
}).ToList();
Maybe it's a good idea to create a view for this on the database (which concatenates the fields for you) and then make EF use this view instead of the original table?
I'm quite sure it's not possible in a LINQ statement or in the Mapping Details.

Categories

Resources