ADO.NET Entity Framework Quirk - c#

When I run the code below, it works
int charId = int.Parse(Request.Params["charId"]);
EveFPT ctx = new EveFPT();
var theCharQuery = from a in ctx.tblChars
where a.id == charId
select new
{
Name = a.name,
CorpName = a.tblCorps.name,
AllianceName = a.tblCorps.tblAlliances.name
};
if(theCharQuery.Count() == 1)
{
var theChar = theCharQuery.First();
lblCharName.Text = theChar.Name;
lblCorpName.Text = theChar.CorpName;
lblAllianceName.Text = theChar.AllianceName;
}
However, If I the below
var theCharQuery = from a in ctx.tblChars
where a.id == charId
select a;
if(theCharQuery.Count() == 1)
{
tblChars theChar = theCharQuery.First();
lblCharName.Text = theChar.name;
lblCorpName.Text = theChar.tblCorps.name;
lblAllianceName.Text = theChar.tblCorps.tblAlliances.name;
}
the statement
theChar.tblCorps
always returns null. Anyone know what's happening?

The Entity Framework doesn't eagerly load child object. You have to check if they're loaded, and then call Load() if they're not.
if(!theChar.tblCorps.IsLoaded)
{
theChar.tblCorps.Load();
}
Here's a good read from MSDN on the subject:
How to: Explicity Load Related Objects (Entity Framework)

I was thinking the same thing, although I wouldn't have expected it to eagerly load in the first example's projection expression either. Once way to try it:
var charId= int.Parse(Request.Params["charId"]);
EveFPT ctx = new EveFPT();
var theChar = ( from a in ctx.tblChars.Include ( "tblCorps" )
where a.id == charId
select new
{
Name = a.name,
CorpName = a.tblCorps.name,
AllianceName = a.tblCorps.tblAlliances.name
} ).FirstOrDefault ();
if(theChar != null)
{
lblCharName.Text = theChar.Name;
lblCorpName.Text = theChar.CorpName;
lblAllianceName.Text = theChar.AllianceName;
}

Related

linq many to many query inside select

Here is my attempt to make a many to many linq request, but it doesn't work as expected. CVVM class has a property ICollection<FormationVM> Formations
var cv = (
from c in context.CVs
where c.Id == id
select new CVVM
{
Id = id,
Formations =
from f in context.Formations
from c2 in context.CVs
where c2.Id == id
select new FormationVM
{
Id = form.Id,
DateDebut = form.DateDebut,
DateFin = form.DateFin,
Ecole = form.Ecole,
Description = form.Description,
Diplome = form.Diplome
}
}).FirstOrDefault();
Why does Model.Formations.Count() return 3 instead of 2 in my View please ?
Ok i found the solution. This code works :
using (Context context = new Context())
{
var cv =
(
from c in context.CVs
where c.Id == id && c.PersonneId == userId
select new CVVM
{
Titre = c.Titre,
MontrerPhoto = c.MontrerPhoto,
Layout = c.Layout,
Id = id,
FormAction = "EditionTraitement",
FormTitre = "Edition de ce CV",
Formations = from form in c.Formations
where c.Id == id && c.PersonneId == userId
select new FormationVM
{
Id = form.Id,
DateDebut = form.DateDebut,
DateFin = form.DateFin,
Ecole = form.Ecole,
Description = form.Description,
Diplome = form.Diplome
}
}).FirstOrDefault();
}

LINQ Filtering Select Ouput with IEnumerable<T>

I have following methods:
Controller:
...
var appmap = Services.GetReqAppMapList(value);
var applist = Services.GetApplicationList(docid, appid, reqid, appmap);
...
Model:
public static IEnumerable<AppMap> GetReqAppMapList(int aiRequestTypeId)
{
try
{
var appmap = new List<AppMap>();
using (var eties = new eRequestsEntities())
{
appmap = (from ram in eties.ReqAppMaps
where ram.IsActive == 1
select new AppMap
{
RequestTypeId = ram.RequestTypeId
}).ToList();
return appmap;
}
}
catch(Exception e)
{
throw e;
}
}
public static IEnumerable<TicketApplication> GetApplicationList(int aiDocumentTypeId, int aiApplicationTypeId, int aiRequestTypeId, IEnumerable<AppMap> appmap)
{
try
{
var applicationlist = new List<TicketApplication>();
using (var applicationentity = new eRequestsEntities())
{
applicationlist = (from app in applicationentity.Applications
where 1==1
<<<Some Conditions Here???>>>
== && appmap.Contains(app.ApplicationTypeId) ==
&& app.IsActive == 1
select new TicketApplication
{
ApplicationId = app.ApplicationId,
Description = app.Description,
DeliveryGroupId = app.DeliveryGroupId,
ApplicationTypeId = app.ApplicationTypeId,
DeliveryTypeId = app.DeliveryTypeId,
DocumentTypeId = app.DocumentTypeId,
SupportGroupId = app.SupportGroupId
}).OrderBy(a => a.Description).ToList();
return applicationlist;
}
And I was thinking how can filter query result of GetApplicationList using the result from GetReqAppMapList
I'm kinda stuck with the fact that I must convert/cast something to the correct type because every time I do a result.Contains (appmap.Contains to be exact), I always get the following error
Error 4 Instance argument: cannot convert from
'System.Collections.Generic.IEnumerable<Test.Models.AppMap>' to
'System.Linq.ParallelQuery<int?>'
You should directly join the two tables in one query.
using (var applicationentity = new eRequestsEntities())
{
applicationlist = (from app in applicationentity.Applications
join ram in applicationentity.ReqAppMaps on app.ApplicationTypeId equals ram.RequestTypeId
where ram.IsActive == 1 && app.IsActive == 1
select new TicketApplication
{
ApplicationId = app.ApplicationId,
Description = app.Description,
DeliveryGroupId = app.DeliveryGroupId,
ApplicationTypeId = app.ApplicationTypeId,
DeliveryTypeId = app.DeliveryTypeId,
DocumentTypeId = app.DocumentTypeId,
SupportGroupId = app.SupportGroupId
}).OrderBy(a => a.Description).ToList();
You can delete the other method if it is not needed anymore. No point hanging onto code which is dead.
Looks like there is no other way to do this (as far as I know), so I have to refactor the code, I hope still that there would be a straight forward conversion and matching method in the future (too lazy). Anyway, please see below for my solution. Hope this helps someone with the same problem in the future. I'm not sure about the performance, but this should work for now.
Controller:
...
var appmap = Services.GetReqAppMapList(value);
var applist = Services.GetApplicationList(docid, appid, reqid, appmap);
...
Model:
<Removed GetReqAppMapList>--bad idea
public static IEnumerable<TicketApplication> GetApplicationList(int aiDocumentTypeId, int aiApplicationTypeId, int aiRequestTypeId)
{
try
{
//This is the magic potion...
List<int?> appmap = new List<int?>();
var applist = (from ram in applicationentity.ReqAppMaps
where ram.RequestTypeId == aiRequestTypeId
&& ram.IsActive == 1
select new AppMap
{
ApplicationTypeId = ram.ApplicationTypeId
}).ToList();
foreach (var item in applist)
{
appmap.Add(item.ApplicationTypeId);
}
//magic potion end
var applicationlist = new List<TicketApplication>();
using (var applicationentity = new eRequestsEntities())
{
applicationlist = (from app in applicationentity.Applications
where 1==1
===>>>&& appmap.Contains(app.ApplicationTypeId)<<<===
&& app.IsActive == 1
select new TicketApplication
{
ApplicationId = app.ApplicationId,
Description = app.Description,
DeliveryGroupId = app.DeliveryGroupId,
ApplicationTypeId =app.ApplicationTypeId,
DeliveryTypeId = app.DeliveryTypeId,
DocumentTypeId = app.DocumentTypeId,
SupportGroupId = app.SupportGroupId
}).OrderBy(a => a.Description).ToList();
return applicationlist;
}
A side-note, C# is a strongly-typed language, just make sure your data types matches during evaluation, as int? vs int etc.., will never compile. A small dose of LINQ is enough to send some newbies circling around for hours. One of my ID-10T programming experience but just enough to remind me that my feet's still flat on the ground.

Listing in WCF Entity

I have a problem with LINQ query (see comment) there is a First method and it only shows me the first element.
When I write in the console "Sales Representative" it shows me only the first element of it as in
I would like to get all of data about Sales Representative. How can I do it?
public PracownikDane GetPracownik(string imie)
{
PracownikDane pracownikDane = null;
using (NORTHWNDEntities database = new NORTHWNDEntities())
{
//Employee matchingProduct = database.Employees.First(p => p.Title == imie);
var query = from pros in database.Employees
where pros.Title == imie
select pros;
// Here
Employee pp = query.First();
pracownikDane = new PracownikDane();
pracownikDane.Tytul = pp.Title;
pracownikDane.Imie = pp.FirstName;
pracownikDane.Nazwisko = pp.LastName;
pracownikDane.Kraj = pp.Country;
pracownikDane.Miasto = pp.City;
pracownikDane.Adres = pp.Address;
pracownikDane.Telefon = pp.HomePhone;
pracownikDane.WWW = pp.PhotoPath;
}
return pracownikDane;
}
Right now you are just getting the .First() result from the Query collection:
Employee pp = query.First();
If you want to list all employees you need to iterate through the entire collection.
Now, if you want to return all the employee's you should then store each new "pracownikDane" you create in some sort of IEnumerable
public IEnumerable<PracownikDane> GetPracownik(string imie) {
using (NORTHWNDEntities database = new NORTHWNDEntities())
{
var query = from pros in database.Employees
where pros.Title == imie
select pros;
var EmployeeList = new IEnumerable<PracownikDane>();
foreach(var pp in query)
{
EmployeeList.Add(new PracownikDane()
{
Tytul = pp.Title,
Imie = pp.FirstName,
Nazwisko = pp.LastName,
Kraj = pp.Country,
Miasto = pp.City,
Adres = pp.Address,
Telefon = pp.HomePhone,
WWW = pp.PhotoPath
});
}
return EmployeeList;
}
Then, with this returned List you can then do what ever you wanted with them.

updating a database record with linq to sql in c#

I have a function that looks like this:
public UpdateRecord(MyObjectModel TheObject, int TheUserID)
{
using (MyDataContextModel TheDC = new MyDataContextModel())
{
var TheObjectInDB = (from o in TheDC.TheObjects
where o.ObjectID == TheObject.ObjectID
select new MyObjectModel()).SingleOrDefault();
if (TheObject.Prop1 != null) { TheObjectInDB.Prop1 = TheObject.Prop1; }
if (TheObject.Prop2 != null) { TheObjectInDB.Prop2 = TheObject.Prop2; }
TheDC.SubmitChanges();
}
}
The code is not crashing but it's not updating the DB. What do I need to change?
select o instead of new MyObjectMode(), Modify:
var TheObjectInDB = (from o in TheDC.TheObjects
where o.ObjectID == TheObject.ObjectID
select o).SingleOrDefault();
First of all you do select new MyObjectModel() in your query which will always create a new object regardsess of what you pull from the database. Change that to select o.
Secondly, in:
if (TheObject.Prop1 != null) { TheObjectInDB.Prop1 = TheObject.Prop1; }
if (TheObject.Prop2 != null) { TheObjectInDB.Prop2 = TheObject.Prop2; }
you update the object's values conditionally. So if Prop1 and Prop2 are null the object's properties won't be updated.
The following code works and it is almost the same as what you posted.
DataContext dc = new DataContext(ConnectionString);
var q = from a in dc.GetTable<Employee>()
where a.EmployeeID == this.EmployeeID
select a;
Employee temp = q.Single<Employee>();
temp.EmployeeActiveStatus = this.EmployeeActiveStatus;
temp.EmployeeName = this.EmployeeName;
temp.EmployeeUserID = this.EmployeeUserID;
temp.EmployeeCreateModifyDate = this.EmployeeCreateModifyDate;
temp.EmployeePaperWork = this.EmployeePaperWork;
dc.SubmitChanges();
The only major difference that I see is the line:
select new MyObjectMode()).SingleOrDefault()

SubSonic 3, build dynamic or expression at runtime

I have a situation where I have to dynamically build a linq query based on user selections.
If I had to dynamically generate sql I could do it this way:
var sb = new StringBuilder();
sb.AppendLine("SELECT * FROM products p");
sb.AppendLine("WHERE p.CategoryId > 5");
// these variables are not static but choosen by the user
var type1 = true;
var type2 = true;
var type3 = false;
string type1expression = null;
string type2expression = null;
string type3expression = null;
if (type1)
type1expression = "p.productType1 = true";
if (type2)
type2expression = "p.productType2 = true";
if (type3)
type3expression = "p.productType3 = true";
string orexpression = String.Empty;
foreach(var expression in new List<string>
{type1expression, type2expression, type3expression})
{
if (!String.IsNullOrEmpty(orexpression) &&
!String.IsNullOrEmpty(expression))
orexpression += " OR ";
orexpression += expression;
}
if (!String.IsNullOrEmpty(orexpression))
{
sb.AppendLine("AND (");
sb.AppendLine(orexpression);
sb.AppendLine(")");
}
// result:
// SELECT * FROM products p
// WHERE p.CategoryId > 5
// AND (
// p.productType1 = true OR p.productType2 = true
// )
Now I need to create a linq query the same way.
This works well with subsonic
var result = from p in db.products
where p.productType1 == true || p.productType2 == true
select p;
I tried it with PredicateBuilder http://www.albahari.com/nutshell/predicatebuilder.aspx but that throws an exception with subsonic.
var query = from p in db.products
select p;
var inner = PredicateBuilder.False<product>();
inner = inner.Or(p => p.productType1 == true);
inner = inner.Or(p => p.productType2 == true);
var result = query.Where(inner);
the exception that is thrown: NotSupportedException: The member 'productType1' is not supported
at SubSonic.DataProviders.MySQL.MySqlFormatter.VisitMemberAccess.
Anybody has an idea how to get this query to work:
Maybe Dynamic LINQ will be helpful?
Here is an usage example, as requested by geocine.
It requires Dynamic Linq.
var productTypes = new int[] {1,2,3,4};
var query = from p in db.products
select p;
if (productTypes.Contains(1))
query.Add("productType1 = #0");
if (productTypes.Contains(2))
query.Add("productType2 = #0");
if (productTypes.Contains(3))
query.Add("productType3 = #0");
if (productTypes.Contains(4))
query.Add("productType4 = #0");
if (productTypes.Count > 0)
{
string result = String.Join(" OR ", productTypes);
query = query.Where("(" + result + ")", true);
}
var result = from p in query
select new {Id = p.ProductId, Name = p.ProductName };
it looks akward but it works.

Categories