Hierarchical select in Entity Framework with lambda expression - c#

I have a relational dataset as dummy. I want to take the data as hierarchical (Role > SubRoles > Permissions) then I will convert to JSON but I get an exception:
Error CS0266
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)
Thanks for your answer.
Model classes:
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public List<SubRole> SubRoles { get; set; }
}
public class SubRole
{
public int Id { get; set; }
public string Name { get; set; }
public string EndPoint { get; set; }
public List<Permission> Permissions { get; set; }
}
public class RoleSubRole
{
public int Id { get; set; }
public int RoleId { get; set; }
public int SubRoleId { get; set; }
}
public class Permission
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SubRolePermission
{
public int Id { get; set; }
public int SubRoleId { get; set; }
public int PermiisonId { get; set; }
}
public class RoleModel
{
public Role Role { get; set; }
}
Program class:
public static void Main(string[] args)
{
RoleModel roleModel = new RoleModel()
{
Role =
(from u in DataSet.Users
join r in DataSet.Roles on u.RoleId equals r.Id
where u.Id == 1
select new Role
{
Name = r.Name,
SubRoles =
(from rsb in DataSet.RoleSubRoles
join sr in DataSet.SubRoles on rsb.SubRoleId equals sr.Id
where r.Id == rsb.RoleId
select new SubRole
{
Name = sr.Name,
EndPoint = sr.EndPoint,
Permissions =
(from srp in DataSet.SubRolePermissions
join p in DataSet.Permissions on srp.PermiisonId equals p.Id
where srp.SubRoleId == sr.Id
select new Permission
{
Name = p.Name
})
})
})
};
}

You should use
Permissions =
(from srp in DataSet.SubRolePermissions
join p in DataSet.Permissions on srp.PermiisonId equals p.Id
where srp.SubRoleId == sr.Id
select new Permission
{
Name = p.Name
}).ToList()
The Permissions is a List<T>, while the query returns an IEnumerable<T>. Same is the case with SubRoles.You need to convert to List<T>, which could be done using the ToList() method
Complete Query
Role =
(from u in DataSet.Users
join r in DataSet.Roles on u.RoleId equals r.Id
where u.Id == 1
select new Role
{
Name = r.Name,
SubRoles =
(from rsb in DataSet.RoleSubRoles
join sr in DataSet.SubRoles on rsb.SubRoleId equals sr.Id
where r.Id == rsb.RoleId
select new SubRole
{
Name = sr.Name,
EndPoint = sr.EndPoint,
Permissions =
(from srp in DataSet.SubRolePermissions
join p in DataSet.Permissions on srp.PermiisonId equals p.Id
where srp.SubRoleId == sr.Id
select new Permission
{
Name = p.Name
}).ToList()
}).ToList()
}).First()
};
Also note that the Role represents a single entity, while the query returns a collection. You need to make a choice on which entity from the collection needs to be stored. For the sample code above, I have used First()

Related

Comparing two table IDs. ASP.NET MVC

I am currently loading two Orders and Colors tables, I wanted the Colors table to list the items that have the ID equal to Orders. For this, what occurred to me was to assign the IdOrders values ​​to a variable and compare it with my IdOrders (in my table Colors), but it is not possible to assign the database's balance to my variable
My tables:
public partial class Orders
{
public int ID_Orders { get; set; }
public Nullable<System.DateTime> Data_Registo { get; set; }
public string Num_Encomenda { get; set; }
public string Ref_Cliente { get; set; }
}
public partial class Colors
{
public int ID_Orders { get; set; }
public int ID_Programa_Malha { get; set; }
public int ID_Linha_Cor { get; set; }
public string Cor { get; set; }
}
I am working with a database already in operation and possible these tables are already used in a sql join but not how to process that information.
As I said the first thing I remembered was to do this:
My Controller:
var id = from d in db.Orders
select d.ID_Orders;
var color = db.Colors.Where(x => x.ID_Orders = id).ToList();
var tables = new EncomendaViewModel
{
Orders= db.Orders.ToList(),
Colors= color.ToList(),
};
return View(tables);
Error in id: CS0029 C# Cannot implicitly convert type to 'int'
Is it possible to process the data in this way?
Thanks for anyone who can help!
-------------------(Update)------------------------------------------------
Using == cs0019 operator '==' cannot be applied to operands of type
My view in Broswer
dbEntities sd = new dbEntities();
List<Orders> orders= sd.Orders.ToList();
List<Colors> colers= sd.Colors.ToList();
var multipletable = from c in orders
join st in colers on c.ID_Programa equals st.ID_Programa into table1
from st in table1.DefaultIfEmpty()
select new MultipleClass { orders= c, colers= st };
There could be one or more values returned from the below query.
var id = from d in db.Orders
select d.ID_Orders;
That is the reason why it was throwing an error.
So lets try it this way
var color = db.Colors.Where(x => id.Contains(x.ID_Orders)).ToList();
public class OrderWithColorsViewModel
{
public Order order { get; set; }
public List<Colors> colers{ get; set; }
}
Public class TestOrderController : Controller
{
public DailyMVCDemoContext db = new DailyMVCDemoContext();
public ActionResult Index()
{
var orders= db.Orders.ToList();
var colers = db.Colors.ToList();
var result = (from c in orders
join st in colers on c.ID_Orders equals st.id into table1
select new OrderWithColorsViewModel { order =c, colers =
table1.ToList() }).ToList();
return View(result);
}
}
credits: YihuiSun

LINQ - SQL Script Changing based on JOIN Order

This is just strange behavior to me.
LINQ transforming my statements creating bizarre execution plans. It's adding sub-queries when I don't ask it to and it's including or excluding joins in this sub-query based on the order of my joins, which leaves me scratching my head. At this point it's impossible for me to optimize this script based on the unpredictable nature of LINQ to Entities.
SETUP
//define global filter
Expression<Func<Contract_SeqExecution, bool>> globalFilter = r => r.ModifiedByFirstName.Contains("w");
...
//extend global filter
Expression<Func<Contract_SeqExecution, bool>> descendantFilter = x => x.client_id == 1 && x.project_status == true && x.parentId != null;
descendantFilter = descendantFilter.And(globalFilter);
//query
IQueryable<Contract_SeqExecution> geDescendantResults = c.queryGroups(this);
//execute
geDescendantResults.AsExpandable().Where(descendantFilter).Dump();
LINQ QUERY
public IQueryable<Contract_SeqExecution> queryGroups(UserQuery context)
{
var result = (from ge in context.group_execution
join aseq in context.automation_sequences on ge.automation_sequence_id equals aseq.id
join modify_u in context.users on aseq.last_modified_by_id equals modify_u.id into modify_uSub
from modify_u in modify_uSub.DefaultIfEmpty()
join p in context.project on aseq.project_id equals p.id
join asstatus in context.automation_sequence_status on ge.run_status_id equals asstatus.id
join es in context.execution_schedule on ge.schedule_id equals es.id
join exe_u in context.users on ge.executed_by_id equals exe_u.id
join create_u in context.users on aseq.created_by_id equals create_u.id
select new Contract_SeqExecution
{
client_id = p.client_id,
project_status = p.status,
ID = ge.id,
Name = aseq.name,
ModifiedByFirstName = modify_u.first_name,
ModifiedByLastName = modify_u.last_name,
FailedInd = asstatus.fail_alert_ind,
parentId = ge.parent_group_exec_id,
patriarchId = ge.patriarch_id
});
return result;
}
If I reorder the joins in the above statement my execution plan changes and LINQ-to-entities decides I want a sub-query....sigh.
Seriously all I did was change the order of the joins in the images below. Drastically different execution plans which will later on hurt performance of the query. What gives? Am I missing something obvious?
Is it picking information up from the entity framework schema? Could it be missing FK definitions or indexes that are driving this crazy behavior? At this point I'm just shooting in the dark. Hopefully someone here can shed some light on this.
Below is the class Contract_SeqExecution. I'm currently running this in a LinqPad C# Program hitting my DAL dll, linq-to-entities.
public class Contract_SeqExecution
{
public int ID { get; set; }
public string Name { get; set; }
public string DisplayName { get; set; }
public int SeqID { get; set; }
public int CaseGroupInd { get; set; }
public string CaseGroupText { get; set; }
public string ExecRatio { get; set; }
public string ModifiedByFirstName { get; set; }
public string ModifiedByLastName { get; set; }
public string Project { get; set; }
public string Uploaded { get; set; }
public string UploadRatio { get; set; }
public bool FailedInd { get; set; }
public bool HoldInd { get; set; }
public int? parentId { get; set; }
public int? patriarchId { get; set; }
public DateTime? SchedRunTime { get; set; }
//other fields
public string Machine {get;set;}
public int is_accepting_changes {get;set;}
public string holding_at_name {get;set;}
public string RunStatus {get;set;}
public string CaseGroupStatus {get; set;}
public string TCStatusColor {get; set;}
public string ExecutedBy {get;set;}
public string CreatedBy {get;set;}
public int? ScheduleID {get;set;}
public bool SeqUploaded {get;set;}
//end other fields
public int? parent_group_exec_id { get; set; }
public int client_id { get; set; }
public bool project_status { get; set; }
public IQueryable<Contract_SeqExecution> queryGroups(UserQuery context)
{
var result = (from ge in context.group_execution
join asstatus in context.automation_sequence_status on ge.run_status_id equals asstatus.id
join es in context.execution_schedule on ge.schedule_id equals es.id
join exe_u in context.users on ge.executed_by_id equals exe_u.id
join aseq in context.automation_sequences on ge.automation_sequence_id equals aseq.id
join p in context.project on aseq.project_id equals p.id
join create_u in context.users on aseq.created_by_id equals create_u.id
join modify_u in context.users on aseq.last_modified_by_id equals modify_u.id into modify_uSub
from modify_u in modify_uSub.DefaultIfEmpty()
select new Contract_SeqExecution
{
client_id = p.client_id,
project_status = p.status,
ID = ge.id,
Name = aseq.name,
ModifiedByFirstName = modify_u.first_name,
ModifiedByLastName = modify_u.last_name,
FailedInd = asstatus.fail_alert_ind,
parentId = ge.parent_group_exec_id,
patriarchId = ge.patriarch_id,
});
return result;
}
}
UPDATE
So I took Andrew's advice and looked into doing this the more "LINQ" way. I like to include FKs in my entities because I feel it's a more natural way to write SQL, habits die hard. I went ahead and rewrote my LINQ expression and the results are now consistent.
Example:
var result = (from ge in context.group_execution
//join asstatus in context.automation_sequence_status on ge.run_status_id equals asstatus.id
//join es in context.execution_schedule on ge.schedule_id equals es.id
//join exe_u in context.users on ge.executed_by_id equals exe_u.id
//join aseq in context.automation_sequences on ge.automation_sequence_id equals aseq.id
//join p in context.project on aseq.project_id equals p.id
//join create_u in context.users on aseq.created_by_id equals create_u.id
//join modify_u in context.users on aseq.last_modified_by_id equals modify_u.id into modify_uSub
//from modify_u in modify_uSub.DefaultIfEmpty()
select new Contract_SeqExecution
{
//client_id = p.client_id,
//project_status = p.status,
ID = ge.id,
Name = ge.automation_sequences.name,
ModifiedByFirstName = ge.automation_sequences.modified_by_user.first_name,
ModifiedByLastName = ge.automation_sequences.modified_by_user.last_name,
//FailedInd = asstatus.fail_alert_ind,
parentId = ge.parent_group_exec_id,
patriarchId = ge.patriarch_id,
});
return result;

Selecting Entity Using Linq query with join and including nested property

I'm battling to retrieve a single Model/Entity using EntityFramework and Linq.
I have a Business with Members, I'm trying to retrieve the users' business based on the BusinessMembers table/entity.
I have the following entities/models:
public partial class Business
{
public Business()
{
BusinessMembers = new HashSet<BusinessMember>();
}
public int ID { get; set; }
public int ID_BusinessStatus { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Phone { get; set; }
public virtual BusinessStatus BusinessStatus { get; set; }
public virtual ICollection<BusinessMember> BusinessMembers { get; set; }
}
and
public partial class BusinessStatus
{
public BusinessStatus()
{
Businesses = new HashSet<Business>();
}
public int ID { get; set; }
[Required]
[StringLength(3)]
public string Code { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
public virtual ICollection<Business> Businesses { get; set; }
}
I then have the following method to return a Single Business Instance:
public Business GetBusinessForUser(string userId)
{
using (var db = new MyContext(_connectionString))
{
var q =
from b in db.Businesses
join bm in db.BusinessMembers on b.ID equals bm.ID_Business
where bm.UserId == userId
select b;
return q.FirstOrDefault();
}
}
Problem I'm having is I want to 'Include' the BusinessStatus for that single Business entity and don't know how to do this.
I need to be able to do:
Business businessEntity = _dataServices.GetBusinessForUser(userId);
if (businessEntity.BusinessStatus.Code == "ACT")
{
// Whatever
}
First, add this to the list of usings
using System.Data.Entity;
Then you can use the .Include() method to load additional children in your query
public Business GetBusinessForUser(string userId)
{
using (var db = new MyContext(_connectionString))
{
var q =
(from b in db.Businesses
join bm in db.BusinessMembers on b.ID equals bm.ID_Business
where bm.UserId == userId
select b).Include(business => business.BusinessStatus);
return q.FirstOrDefault();
}
}
I would also avoid using the join method explicitly. If your model has correct relationships (e.g. foreign keys), you should be able to just do this:
var q = db.Businesses
.Where(b => b.BusinessMembers.Any(bm => bm.UserId == userId))
.Include(b => b.BusinessStatus);
return q.FirstOrDefault();
or even
var q = db.BusinessMembers
.Where(bm => bm.UserId == userId)
.Select(bm => bm.Business)
.Include(b => b.BusinessStatus);

Cannot implicitly convert type 'List<AnonymousType#1>' to 'IEnumerable<Models.APPLICANT>'

Trying To Left Join 2 Tables
public IEnumerable<APPLICANT> GetApplicant()
{
IEnumerable<APPLICANT> applicantdata = Cache.Get("applicants") as IEnumerable<APPLICANT>;
if (applicantdata == null)
{
var applicantList = (from a in context.Profiles
join app in context.APPLICANTs
on a.PROFILE_ID equals app.Profile_id into joined
from j in joined.DefaultIfEmpty()
select new
{
Profiles = a,
APPLICANTs= j,
}).Take(1000);
applicantdata = applicantList.AsQueryable().OrderBy(v => v.APPLICANT_ID).ToList();
if (applicantdata.Any())
{
Cache.Set("applicants", applicantdata, 30);
}
}
return applicantdata;
}
But the problem is that im having error at the last Line
applicantdata = applicantList.AsQueryable().OrderBy(v => v.APPLICANT_ID).ToList();
The error says
Error 1 Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.IEnumerable<Models.APPLICANT>'. An explicit conversion exists (are you missing a cast)
THIS IS MY APPLICANT CLASS
[DataContract(IsReference = true)]
public partial class APPLICANT
{
[DataMember]
public int APPLICANT_ID { get; set; }
[DataMember]
public string APPLICANT_LastName { get; set; }
[DataMember]
public string APPLICANT_FirstName { get; set; }
[DataMember]
public string APPLICANT_MiddleName { get; set; }
[DataMember]
public string APPLICANT_Address { get; set; }
[DataMember]
public string APPLICANT_City { get; set; }
[DataMember]
public string APPLICANT_Phone { get; set; }
[DataMember]
public string APPLICANT_Email { get; set; }
[DataMember]
public Nullable<int> Profile_id { get; set; }
It is the type of the collections that is the problem.
IEnumerable<APPLICANT> applicantdata ...
is not equal to the type you get from this expression:
var applicantList =
(from a in context.Profiles
join app in context.APPLICANTs
on a.PROFILE_ID equals app.Profile_id into joined
from j in joined.DefaultIfEmpty()
select new //<-- this is what dicides the type of the applicationList
{
Profiles = a,
APPLICANTs= j,
}).Take(1000);
this mean that you cannot do this:
applicantdata = applicantList...
I think you need to do something like this:
applicantdata = applicantList
.SelectMany(c => c.APPLICANTs) //this line added
.AsQueryable().OrderBy(v => v.APPLICANT_ID).ToList();
UPDATE
If you are using my "solution" with SelectMany, you should be asking yourself - "Am I extracting the right data when I create applicationList..?"
perhaps this is better..:
var applicantList =
(from a in context.Profiles
join app in context.APPLICANTs
on a.PROFILE_ID equals app.Profile_id into joined
from j in joined.DefaultIfEmpty()
select j //<-- this is APPLICANTs type
}).Take(1000);
I think your issue is not converting from a list to an IEnumerable. Instead, the problem is that you cannot convert an LIST of annonoymous object to an IEnumerable of APPLICANT.
You should modify your select statement so you're selecting an APPLICANT.

Given a list of items, each containing a subitem, get the subitems and remove duplicates

Given a list of groupos, where each groupo has a single empresa and multiple groupos can have the same empresa, how do you get the empresas that contain any of the list's groupos?
I have this Model:
public class Grupo
{
public int id { get; set; }
public string descripccion { get; set; }
[ForeignKey("Empresas")]
public int empresa { get; set; }
public virtual empresa Empresas { get; set; }
}
public class empresa
{
public int id { get; set; }
public string descripcion { get; set; }
public virtual ICollection<Grupo> Grupos { get; set; }
}
So this method gives me a List
private List<Grupo> VerEmpresas(int userId)
{
var lista = (from ga in db.GrupoAccesos
join g in db.Grupos
on ga.grupo equals g.id
where ga.usuario == userId
select g).ToList();
return lista;
}
and now I want to use this method to show me the empresas that are related to grupo.
Below emp gives a bool, and instead I want all the empresas that are in my list of grupos.
List<Grupo> verEmpresa = VerEmpresas(1);
var emp = (from p in db.Empresas
select p.Grupos).Contains(verEmpresa);
ViewBag.empresa = new SelectList(emp, "id", "descripcion");
You can try getting the empresa ids from your Grupo list and using the foreign key relationship to get the empresas:
var empresaIds = verEmpresa.Select( v => v.empresa ).Distinct().ToList();
var emp = from p in db.Empresas
where empresaIds.Contains( p.id )
select p;
In your code you are passing 'VerEmpresa' which is a list of Grupo. You should pass one object of Grupo from that list. Try using Any and All method on verEmpresa List.
Try something like:
from p in db.Empresas
where verEmpresa.Any(val => p.Contains(val))
select p;
If all you want is the empresas, try:
var emp = (from e in db.Empresas
from g in db.Grupos
where e.Grupos.Contains(g)
select e);

Categories

Resources