Trying to convert an entity object to local object so i can use it for further transformations.
Here is the code that i am using to convert the entity object;
IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea
select new SystemArea
{
SystemAreaId = sa.SystemAreaId,
SystemAreaCode = sa.SystemAreaCode,
SystemAreaType = sa.SystemAreaType,
SystemAreaDescription = sa.SystemAreaDescription,
SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
SystemAreaStatus = sa.SystemAreaStatus,
Count = sa.systemareafunctionality.Count,
SystemAreaFunctionality = sa.systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
}).ToList();
Here the count variable is to confirm whether there is any child data in it.
SystemAreaFunctionality is the child object that i am trying to convert here by using SELECT function but it is always blank collection. Rest data is getting assigned to parent object but the only thing missing here is the child table records. Where am i going wrong, please help!
Generated SQL :
SELECT
`Project3`.`C1`,
`Project3`.`SystemAreaId`,
`Project3`.`SystemAreaCode`,
`Project3`.`SystemAreaType`,
`Project3`.`SystemAreaDescription`,
`Project3`.`SystemAreaCreatedDate`,
`Project3`.`SystemAreaUpdateDate`,
`Project3`.`SystemAreaStatus`,
`Project3`.`C3` AS `C2`,
`Project3`.`C2` AS `C3`,
`Project3`.`SystemAreaCode1`
FROM (SELECT
`Project1`.`SystemAreaId`,
`Project1`.`SystemAreaCode`,
`Project1`.`SystemAreaType`,
`Project1`.`SystemAreaDescription`,
`Project1`.`SystemAreaCreatedDate`,
`Project1`.`SystemAreaUpdateDate`,
`Project1`.`SystemAreaStatus`,
1 AS `C1`,
`Project2`.`SystemAreaCode` AS `SystemAreaCode1`,
`Project2`.`C1` AS `C2`,
`Project1`.`C1` AS `C3`
FROM (SELECT
`Extent1`.`SystemAreaId`,
`Extent1`.`SystemAreaCode`,
`Extent1`.`SystemAreaType`,
`Extent1`.`SystemAreaDescription`,
`Extent1`.`SystemAreaCreatedDate`,
`Extent1`.`SystemAreaUpdateDate`,
`Extent1`.`SystemAreaStatus`,
(SELECT
COUNT(1) AS `A1`
FROM `systemareafunctionality` AS `Extent2`
WHERE `Extent1`.`SystemAreaCode` = `Extent2`.`SystemAreaCode`) AS `C1`
FROM `systemarea` AS `Extent1`) AS `Project1` LEFT OUTER JOIN (SELECT
`Extent3`.`SystemAreaCode`,
1 AS `C1`
FROM `systemareafunctionality` AS `Extent3`) AS `Project2` ON `Project1`.`SystemAreaCode` = `Project2`.`SystemAreaCode`) AS `Project3`
ORDER BY
`Project3`.`SystemAreaCode` ASC,
`Project3`.`C2` ASC
JSON output:
[{"SystemAreaId":1,"SystemAreaCode":"KIO","SystemAreaType":"KIOSK","SystemAreaDescription":"tasks
related to
receptionist","SystemAreaCreatedDate":"/Date(1543421018000)/","SystemAreaUpdateDate":"/Date(1543421018000)/","SystemAreaStatus":true,"SystemAreaFunctionality":[],"Count":1}]
PS : Please don't suggest automapper or extension methods. Thanks!
OPINION :
Took me two days to make MySQL(latest version) work with EF and trust me it was painstaking and on the contrary EF with MSSQL is so simple and easy to implement.
One thing i experienced is that Oracle is not interested in providing support for the free version of MySQL whatsoever, so they are being sloppy on the documentation of new version and are providing unstable .NET connectors.
ACTUAL ANSWER :
EF was behaving so weirdly, that it would only load the data in the child entity (SystemAreaFunctionality) only if i asked EF to load the child of the child entity (i.e. SystemAreaFunctionalityEmployeeRoleMapping which is child to SystemAreaFuncionality), which also means that i had to take unnecessary data.
So my link query looks like this :
var result = (from sa in CurrentContext.systemarea
select new SystemArea
{
SystemAreaId = sa.SystemAreaId,
SystemAreaType = sa.SystemAreaType,
Count = sa.systemareafunctionality.Count,
SystemAreaFunctionalities = sa.systemareafunctionality.Select(saf => new SystemAreaFunctionality
{
SystemAreaId = saf.SystemAreaId,
SystemAreaFunctionalityController = saf.SystemAreaFunctionalityController,
SystemAreaFunctionalityAction = saf.SystemAreaFunctionalityAction,
SystemAreaFunctionalityType = saf.SystemAreaFunctionalityType,
SystemAreaFunctionalityEmployeeRoleMappings = saf.systemareafunctionalityemployeerolemapping.Select(saferm => new SystemAreaFunctionalityEmployeeRoleMapping
{
SystemAreaFunctionalityEmployeeRoleMappingId = saferm.SystemAreaFunctionalityEmployeeRoleMappingId,
SystemAreaFunctionalityCreatedDate = saferm.SystemAreaFunctionalityCreatedDate
})
})
}).ToList();
ALTERNATIVELY :
Tried using the same linq query (posted in OP) with different database this time with PostgreSQL plus npgsql connector and surprisingly EF gives me exactly what i want with out extra baggage.
On top of that PostgreSQL gives better performance with EF than MySQL. So i presume that switching to PostgreSQL would be a better option.
PS : If you are deciding on open sources DBMS then please refer this before jumping in with MySQL :
https://www.youtube.com/watch?v=emgJtr9tIME
https://www.reddit.com/r/csharp/comments/40x3nx/which_orm_is_the_right_choice_for_mysql
Use this:
CurrentContext.systemarea.Include('systemareafunctionality')
or
IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea
join systemareafunctionality in CurrentContext.systemareafunctionality on sa.systemareafunctionalityID equals systemareafunctionality.ID
select new SystemArea
{
SystemAreaId = sa.SystemAreaId,
SystemAreaCode = sa.SystemAreaCode,
SystemAreaType = sa.SystemAreaType,
SystemAreaDescription = sa.SystemAreaDescription,
SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
SystemAreaStatus = SystemAreaStatus,
Count = systemareafunctionality.Count,
SystemAreaFunctionality = systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
}).ToList();
or
IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea
join systemareafunctionality in CurrentContext.systemareafunctionality on sa.systemareafunctionalityID equals systemareafunctionality.ID into item1 from subitem1 in item1.DefaultIfEmpty()
select new SystemArea
{
SystemAreaId = sa.SystemAreaId,
SystemAreaCode = sa.SystemAreaCode,
SystemAreaType = sa.SystemAreaType,
SystemAreaDescription = sa.SystemAreaDescription,
SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
SystemAreaStatus = SystemAreaStatus,
Count = systemareafunctionality.Count,
SystemAreaFunctionality = systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
}).ToList();
Apparently your CurrentContext is a Dbcontext with at least a table of SystemAreas and a table of SystemAreaFunctionalities.
It seems that every SystemArea has zero or more SystemAreaFunctionalities; every SystemAreaFunctionality belongs to exactly one SystemArea, a straightforward one-to-many relationship using a foreign key.
Note: it might be that you have a many-to-many relation, the answer will be similar
Alas you forgot to write your classes, so I'll give a shot:
class SystemArea
{
public int Id {get; set;}
... // other properties
// every SystemArea has zero or more SystemAreaFunctionalities (one-to-many)
public virtual ICollection<SystemAreaFunctionality> SystemAreaFunctionalities {get; set;}
}
class SystemAreaFunctionality
{
public int Id {get; set;}
... // other properties
// every SystemAreaFunctionality belongs to exactly one SystemArea, using foreign key
public int SystemAreaId {get; set;}
public virtual SystemArea SystemArea {get; set;}
}
In entity framework the columns of your tables are represented by non-virtual properties, the virtual properties represent the relationships between the tables. (one-to-many, many-to-many, ...)
for completeness:
class CurrentContext : DbContext
{
public DbSet<SystemArea> SystemAreas {get; set;}
public DbSet<SystemAreaFunctionality> SystemAreaFunctionalities {get; set;}
}
If people want items with their sub-items, like Schools with their Students, Customers with their Orders, etc. people tend to perform a (group)Join. However, when using entity framework joins are seldom necessary. Ise the ICollections instead. Entity framework knows the relationships and knows which (group)join to perform.
Regularly I see people use Include, but if you do that, you'll select the complete object, which is not very efficient. Suppose you have a SystemArea with Id = 10, and 1000 SystemAreaFunctionalities, you know that every SystemAreaFunctionality has a foreign key SystemAreaId with a value 10. Instead of sending this value only once as primary key of SystemArea, Include will also select all 1000 foreign keys with this value 10. What a waste of processing power!
When querying data, always use Select and select only the properties you actually plan to use. Only use Include if you plan to Update the included object.
You wrote:
SystemAreaFunctionality is the child object that i am trying to convert here...
It is not clear what you really want. Do you want a collection of all used SystemAreaCodes? Or do you really want a collection of new SystemAreaFunctionalities where only one field is filled: SystemAreaCode? Because of you use of singular property name, it seems you don't want a collection but only one item.
var result = currentContext.SystemAreas.Select(systemArea => new
{
Id = systemArea.Id,
Code = systemArea.Code,
...
// if you want a collection of SystemAreaFunctionalities
// where every SystemAreaFunctionality is filled with only SysemAreaCode
// do the following:
SystemAreaFunctionalities = systemArea.SystemAreaFunctionalities
.Select(systemAreaFunctionality => new SystemAreFunctionality
{
SystemAreaCode = systemAreaFunctionality.SystemAreaCode,
})
.ToList(), // DON'T FORGET THIS, OR YOU WON'T GET RESULTS!
})
.ToList()
}
I think the cause of your empty SystemAreaFunctionalities is because you forgot to do ToList().
Because you used ToList(), you automatically have the Count of the selected SystemAreaFunctionalities. There is no need to select this Count separately.
One of the slower parts of database queries is the transport of the selected data from the database management system to your local process. It is good practice to only select data you actually plan to use
You query is not very efficient because you select complete SystemAreaFunctionalities and fill only the SystemAreaCode. All other fields will be filled by default values. Apart from the slower query, you also give your callers the impression that they get properly filled SystemAreaFunctionalities. An improved version would be:
var result = currentContext.SystemAreas.Select(systemArea => new
{
// select only the properties you actually plan to use
Id = systemArea.Id,
Code = systemArea.Code,
...
// if you only need the SystemAreaCodes, select only that property
SystemAreaCodes = systemArea.SystemAreaFunctionalities
.Select(systemAreaFunctionality => systemAreaFunctionality.SystemAreaCode)
.ToList(),
})
.ToList()
};
Of courds, if you need mrre than only the SystemAreaCodes, but several SystemAreaFunctionalities, go ahead, select them:
...
SystemAreaFunctionalities = systemArea.SystemAreaFunctionalities
.Select(systemAreaFunctionality => new
{
// again: select only the properties you plan to use!
Id = systemAreaFunctionality.Id
SystemAreaCode = systemAreaFunctionality.SystemAreaCode,
})
An include should do the trick for you like so:
IEnumerable<SystemArea> result = (from sa in CurrentContext.systemarea.Include("systemareafunctionality")
select new SystemArea
{
SystemAreaId = sa.SystemAreaId,
SystemAreaCode = sa.SystemAreaCode,
SystemAreaType = sa.SystemAreaType,
SystemAreaDescription = sa.SystemAreaDescription,
SystemAreaCreatedDate = sa.SystemAreaCreatedDate,
SystemAreaUpdateDate = sa.SystemAreaUpdateDate,
SystemAreaStatus = sa.SystemAreaStatus,
Count = sa.systemareafunctionality.Count,
SystemAreaFunctionality = sa.systemareafunctionality.Select(e => new SystemAreaFunctionality { SystemAreaCode =e.SystemAreaCode })
}).ToList();
Is there any better way to merge a Entity Table with a Entity View
A little example: I have a Person table with:
id,
name,
lastname
columns and a view named ViewPersonLastLocations with:
person_id
location_name.
I need to display Person table with the information of ViewPersonLastLocations.
Actually i can "merge" those entities with two foreachs, and i create a variable in the Person partial class.
Is there any other way to do this?
I am a little unclear on what you want based on your last comment, but will start with this code for a join if the relationship is 1:1. If it is 1:Many, then it is similar, but project into a collection.
var personWithLocation = context.Persons
.SelectMany(p => context.ViewPersonLastLocations
.Where(vp => vp.person_id == p.id)
.DefaultIfEmpty(),
(p, vp) => new PersonViewModel // create a viewmodel for results or anonymous
{
Id = p.id,
Name = p.name,
LastName = p.lastname,
LocationName = vp.location_name
}
).ToList();
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
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
I have this classic scenario where I have a User table and a Contact table containing only UserId and ContactId columns (so it is a self many to many relationshsip). What I would like is a query that gives me a list of userIds with number of common contacts with the specified User. In plain old SQL I have the following query (contacts of user and user itself is filtered out to get facebook like friend suggestions):
SELECT COUNT(c1.ContactId) as CommonContact, c2.UserId
from Contacts as c1
inner join Contacts as c2 on c1.ContactId = c2.ContactId
Where c1.UserId = #Id AND c2.UserId != #Id
AND c2.UserId NOT IN (SELECT ContactId from Contacts Where UserId = #Id)
Group By c2.UserId
ORDER BY CommonContact Desc
This simple query works great but I can not figure out how to write the same query in LINQ to Entity, because in the Entity Framework model I have User entity that entity have Contact navigation property but the connection table is not there directly....
Thanks a lot for any help...
Didn't have time and try to run it but something like this should work.
public class Test
{
//simulate an IQueryable
private readonly IQueryable<Person> _people = new List<Person>().AsQueryable();
public void FindContactMatchCount(Guid personId)
{
//we'll need the list of id's of the users contacts for comparison, we don't need to resolve this yet though so
//we'll leave it as an IQueryable and not turn it into a collection
IQueryable<Guid> idsOfContacts = _people.Where(x => x.Id == personId).SelectMany(x => x.Contacts.Select(v => v.Id));
//find all the people who have a contact id that matches the selected users list of contact id's
//then project the results, this anonymous projection has two properties, the person and the contact count
var usersWithMatches = _people
.Where(x => idsOfContacts.Contains(x.Id))
.Select(z => new
{
Person = z, //this is the person record from the database, we'll need to extract display information
SharedContactCount = z.Contacts.Count(v => idsOfContacts.Contains(v.Id)) //
}).OrderBy(z => z.SharedContactCount)
.ToList();
}
}