I have a public method called LoadContact() in the Contact class. I want to load the contact data using Linq and assign the values to 'this' instance.
So far I have .....
var contact = (from cont in db.Contacts
from note in db.Contacts_Notes.Where(n => n.ContactID == cont.ContactID).DefaultIfEmpty()
where cont.AccountID == this.AccountID && cont.ContactID == this.ContactID
select new Contact
{
AccountID = cont.AccountID,
CompanyName = cont.CompanyName,
ContactID = cont.ContactID,
Firstname = cont.Firstname,
JobTitle = cont.JobTitle,
Lastname = cont.Lastname,
Notes = note.Note
}).SingleOrDefault();
if(contact != null)
{
this.AccountID = contact.AccountID;
this.CompanyName = contact.CompanyName etc etc etc
}
.,.. but this seems really long winded. How can I assign the results directly to the current instance?
Is there a reason why you don't make it a static method which return a new contact? The way you wants to do it looks like bad design (depending on why you do it).
I would suggest you made it static so it could be used like:
var contact = Contact.Load(...);
instead of
var contact = new Contact();
contact.LoadContact(...);
This way you would be able to just return the contact you found with your query like:
public static Load(int contactID, int accountID) //If they are integers
{
return (from cont in db.Contacts
from note in db.Contacts_Notes.Where(n => n.ContactID == cont.ContactID).DefaultIfEmpty()
where cont.AccountID == accountID && cont.ContactID == contactID
select new Contact
{
//... stuff
}).SingleOrDefault();
}
This is exactly the problem that Automapper was built to solve. Recommended!
There is no way to do that because LINQ is made to query and get results back, so you will always need to iterate through the list or get one item from the list and do your thing with it.
Just a thought: what about:
var contact = (from cont in db.Contacts
from note in db.Contacts_Notes.Where(n => n.ContactID == cont.ContactID).DefaultIfEmpty()
where cont.AccountID == this.AccountID && cont.ContactID == this.ContactID
select this.RenewSelf(
cont.AccountID,
cont.CompanyName,
cont.ContactID,
cont.Firstname,
cont.JobTitle,
cont.Lastname,
note.Note
).SingleOrDefault();
Not too pretty, but if you implement the private method RenewSelf it is at least more readable and less "long-winded". Other options exist, think of something like AutoMapper, as somebody else already suggested.
PS: normally, the DAO layer is not built inside the POCO, which is a sign of "code smell". Just meaning to say, maybe you should change your technical design to a more robust method where POCOs and DAO are separated, in which case this problem will not even occur anymore (i.e., the Load, Save etc methods are part of the DAO and take a POCO, here a Contact object, as input or result).
Related
I have two tables (tbPerson and tbDataLog) where I need to return Id from one table (tbPerson) after checking certain conditions on both. After this, this result should be passed to another query. My first query returns the Id (primary key of a table) successfully and I need to pass these ids to another query so that it return me data based upon these Id. I also has an IQueryable type base object to check certain conditions to fetch data.
IQueryable<tbPerson> dataset
and I cannot changes this from Iqueryable to other as it will break other part of the code)
My first linq statement:
public static IQueryable<LogResults> GetResultsForYes()
{
Databasename ents = new Databasename();
var ids = (from f in ents.tbPerson
join g in ents.tbDataLog
on f.InfoID equals g.RefId
where g.Tag == "subscribed" && g.OldValue == "No" && g.Action == "Modified"
select new LogResults { _LogID = f.Id }).OrderBy(x => x._LogID);
return ids;
}
public class LogResults
{
public int _LogID { get; set; }
}
I access my result something like this where I can see in debugger all the Ids.
IQueryable<LogResults> log = GetResultsForYes();
Problem comes, when I tried to get records from tbPerson based upon these returned Id.
dataset=log.where(x=>x._LogID != 0);
I get this error:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IQueryable'. An explicit conversion exists(are you missing a cast)?
Any suggestions or some other good approach is welcome.
I love this thing about stackoverflow. when we write questions we force our brain to think more deeply and after 30 mins of posting this question, I solved it in a simple way. Sometimes we overcomplicated things!
var ids = (from f in ents.tbPerson
join g in ents.tbDataLog
on f.InfoID equals g.RefId
where g.Tag == "subscribed" && g.OldValue == "No" && g.Action == "Modified"
select new { f.Id }).ToArray();
var allId = ids.Select(x => x.Id).ToArray();
dataset = dataset.Where(x => allId.Contains(x.Id));
#ankit_sharma : I have not tested yours but will give a try and come back to you. Thanks for giving time and effort.
IQueryable<tbPerson> dataset=log.where(x=>x._LogID != 0);
The result of log.where(x=>x._LogID != 0) is an IQueryable<LogResults>, and you are trying to assign this result to dataset of type IQueryable<tbPerson>, two diferent types.
EDIT:
I see you make a join to get the tbPerson ids, and then you do a second query to get the persons. You could get the persons in the first join.
I just modify your code:
IQueryable<tbPerson> persons = from person in ents.tbPerson
join g in ents.tbDataLog
on person.InfoID equals g.RefId
where g.Tag == "subscribed" && g.OldValue == "No" && g.Action == "Modified"
select person;
What I am asking is actually a little more broad than the question title...but that is kind of the specific question.
I am trying to thin out my controllers and move all business logic / interaction with Entity Framework into a Service Layer so that my controllers don't need the context at all, which I believe is the "right" way to do things.
The problem is that when I create a Service Layer method that returns a domain model, it does not contain the Navigation Properties and once I am calling this method in my controller and need to access these navigation properties, the context has already been disposed. This then forces me to make multiple calls out to other Service Layer methods to get the rest of the properties I need so that I can create my View Model.
I'm sure the issue is that I am not creating my methods in the proper way or missing some component of the correct architecture for this situation so here is some code to demonstrate what I am doing.
Service Layer method:
public IEnumerable<Paper> GetPapersForReview(int userID, string courseID, string role)
{
using (USGEntities context = new USGEntities())
{
IEnumerable<Paper> models = (from a in context.Papers
join b in context.Users_Roles on a.Paper_Types.Course_ID equals b.Course_ID
where a.Status == "REV" && a.Deleted == false && b.User_ID == userID && b.Role.Name == role && b.Course_ID == courseID
select a).ToList();
return models;
}
}
Controller method:
public JsonResult GetPapersForReview(string courseID)
{
int user_id = new User().GetUserIDByDomainAccount(User.Identity.Name);
var vm = (from a in new PaperService().GetPapersForReview(user_id, courseID, "Reviewer")
select new PaperViewModel()
{
Paper_ID = a.ID,
Proposal_ID = a.Proposal_ID,
Expected_Start_Date = a.Expected_Start_Date
}).Distinct().ToList();
foreach (var paper in vm)
{
Proposal proposal = new ProposalService().GetProposal(paper.Proposal_ID);
Paper_Types paper_type = new PaperTypeService().GetPaperTypeByPaper(paper.Paper_ID);
paper.Paper_Type = paper_type.Description;
paper.Resources = new PaperService().GetResourceList(paper.Paper_ID);
paper.Proposal_Title = proposal.Title;
paper.Author = new UserService().GetNameByUserID(proposal.Author_User_ID);
}
return Json(vm, JsonRequestBehavior.AllowGet);
}
So you can see after I make the call to the Service Layer method and get the properties that I have direct access to, I then have to loop back through that and make additional calls to get the rest of the properties that I need. I know this is not the right way to do things. So how do I structure things better to return everything I need from the Service Layer?
Some other related questions are: should I be returning IEnumerables or something else from the Service Layer and do I need to be calling ToList() in both places?
You have the .Include extension:
public IEnumerable<Paper> GetPapersForReview(int userID, string courseID, string role)
{
using (USGEntities context = new USGEntities())
{
var result = context.Papers
.Include(paper => paper.User)
.Where(paper => paper.Status == "REV" && paper.Deleted == false && paper.User_ID == userID && paper.User.Role.Name == role && paper.Course_ID == courseID)
.ToList();
return result;
}
}
You can even use .ThenInclude if you have multiple levels:
.Include(p => p.Item)
.ThenInclude(p => p.SubItem)
Let me first explain what I'm trying to accomplish.
I'm working with a C# ASP.NET MVC 5 project using Entity Framework to communicate with a SQL Server database. Most of the queries utilizes linq for its queries. In various places on the frontend site I'm displaying lists of records and need to provide the means of searching these records via a search bar. The initial idea right now is to allow the user to enter a search phrase with keywords being separated by spaces, and those keywords are used to match any combination of fields in the records of a table.
For example, say my search is "John Doe" against a user table. Consider these being the records in this table:
uFirstName uLastName
---------- ----------
Johnny Doe
John Doe
Jane Doe
The first two records should be returned.
Here's an example method I would call to return the results I expect:
public static List<UserModel> GetUserList(string terms)
{
using (DBConnection dbcontext = new DBConnection())
{
var termlist = (terms == "") ? new List<string>() : terms.Split(' ').ToList();
var linqList = (from u in dbcontext.Users
where
(
(terms == "") ||
(termlist.Any(_s => u.uLastName.Contains(_s))) ||
(termlist.Any(_s => u.uFirstName.Contains(_s)))
)
select new { u.uLastName, u.uFirstName });
return linqList.ToList().ConvertAll<UserModel> ( u => new UserModel { LastName = u.uLastName, FirstName = u.uFirstName } );
}
}
In my project I'm utilizing this search bar in various places being used to search against a variety of tables that obviously have different fields. What I would like to do is create a helper method that allows me to pass in the "terms" string and have it matched against a list of field values within the linq statement generically. Here's an example pseudo method that shows what I would like to change the above method to:
public static List<UserModel> GetUserList(string terms)
{
using (DBConnection dbcontext = new DBConnection())
{
var linqList = (from u in dbcontext.Users
where SearchTermMatch(terms, new List<string>() { u.uLastName, u.uFirstName }) == true
select new { u.uLastName, u.uFirstName });
return linqList.ToList().ConvertAll<UserModel>(u => new UserModel { LastName = u.uLastName, FirstName = u.uFirstName });
}
}
And this is what the helper method would look like:
public static bool SearchTermMatch(string terms, List<string> fieldvalues)
{
if (terms == "") return true;
else
{
var termlist = terms.Split(' ').ToList();
var foundlist = new List<bool>();
foreach (string value in fieldvalues)
foundlist.Add(termlist.Any(s => value.Contains(s)));
return foundlist.Any(f => f == true);
}
}
Even though this compiles fine, at runtime it produces the following error:
LINQ to Entities does not recognize the method 'Boolean SearchTermMatch(System.String, System.Collections.Generic.List`1[System.String])' method, and this method cannot be translated into a store expression.
From all my searching on how to get this working, it's clear I need to utilize Expressions, but I can't for the life of me understand how those work. What I do understand is that Entity Framework wants to convert the linq statements into a query that SQL can understand, and my helper method isn't equipped to do so.
Ultimately what I want to accomplish is to build a helper method that I can later expand upon with more advanced searching techniques. I figure if I start simple with a search on all relevant fields based on a keyword split, I can later add more complexity that I would only have to do to this helper method and all my search bars will benefit from those advancements.
So I guess what I'm looking for is your help on how I can create this helper method that I can use throughout my various linq statements in my project.
Ok, I found a solution to my question. It's not completely ideal, but it gets the job done.
Let me first give reference to the sources I'm using for my solution. I first referred to this answer as the starting point:
https://stackoverflow.com/a/27993416/4566281
This answer referred to a source that I ended up using in my project. If you're using Visual Studio, you can find the package in NuGet, just search for "neinlinq", or get it from this GitHub repository:
https://github.com/axelheer/nein-linq
The only reason I don't consider this my ideal solution is that I was hoping to stick completely to the libraries in .NET / MVC. There's nothing wrong with using a 3rd party library, and in this case, it got the job done for me. But I was hoping to accomplish this as native as possible, and within reason.
So on to my code solution, as I hope this will help someone else in some capacity.
My "helper" function(s) ended up being this (don't forget to include "using NeinLinq;")
[InjectLambda]
public static bool SearchTermMatch(List<string> termlist, List<string> fieldvalues)
{
throw new NotImplementedException();
}
public static Expression<Func<List<string>, List<string>, bool>> SearchTermMatch()
{
return (t,f) =>
(
(t.Count() == 0) ||
(t.Count(_t => f.Any(_f => _f.Contains(_t)) || _t == "") == t.Count())
);
}
And, my linq statement ended up being the following:
public static List<UserModel> GetUserList(string terms)
{
using (DBConnection dbcontext = new DBConnection())
{
var termlist = (terms == "") ? new List<string>() : terms.Split(' ').ToList();
var linqList = (from u in dbcontext.Users
where SearchTermMatch(termlist, new List<string>() { u.uLastName, u.uFirstName })
select new { u.uLastName, u.uFirstName });
return linqList.ToList().ConvertAll<UserModel>(u => new UserModel { LastName = u.uLastName, FirstName = u.uFirstName });
}
}
I also didn't like that I have to construct the "termlist" before the linq statement in order to make the comparisons I wanted. Ideally I'd like to have the "SearchTermMatch" expression to construct the list through something similar to Split so all I had to do was pass in the string "terms", but I couldn't figure out how to accomplish that in the expression. If someone has an idea on how to do that please let me know. I could then have the flexibility to establish my own set of search rules in the expression instead of having the calling linq statement make the list.
So, to come full circle on how this accomplishes my sitution, I can now repurpose SearchTermMatch for all my search bar scenarios. Take for example this statement:
var linqList = (from p in Person
join a in Address on p.AddressID equals a.AddressID
select new { p.ContactName, p.EmailAddress, a.Street, a.City, a.State, a.Zipcode });
I can now easily update it to the following to handle my search bar call:
var termlist = (terms == "") ? new List<string>() : terms.Split(' ').ToList();
var linqList = (from p in Person
join a in Address on p.AddressID equals a.AddressID
where SearchTermMatch(termlist, new List<string>() { p.ContactName, p.EmailAddress, a.Street, a.City, a.State, a.Zipcode })
select new { p.ContactName, p.EmailAddress, a.Street, a.City, a.State, a.Zipcode });
Hi this is my first question so apologies if it is really basic - I am very new to programming!!!
Using c# in MVC I am trying to select object which has a Date property from entitymodel context. This date then selects the relevant Weight object and so on to get my list of "Set" objects.
The code works and does what I want but would like some general guidance on how to make this code more concise. Here is the code:
public ActionResult showDiary(string datein)
{
LocalTestEntities1 dblists = new LocalTestEntities1();
DateTime date = Convert.ToDateTime(datein);
IEnumerable<ExerciseDiary> diary = from o in dblists.ExerciseDiaries where o.Date == date select o;
var mydiary = diary.ToList();
ExerciseDiary thediary = mydiary[0];
IQueryable<Weight> weights = from o in dblists.Weights where o.DiaryID == thediary.ID select o;
var selectedWeight = weights.ToList();
Weight weight = selectedWeight[0];
IEnumerable<Set> sets = from x in dblists.Sets where x.WeightId == weight.WeightID select x;
return View(sets);
}
It seems that I am taking too many steps here. I know that I am only returning one object to diary. Is there a way to get this object from dblists without sending to an IEnumerable?
Using the First() method will make things a little more concise:
public ActionResult showDiary(string datein)
{
using (LocalTestEntities1 dblists = new LocalTestEntities1())
{
DateTime date = Convert.ToDateTime(datein);
var thediary = (from o in dblists.ExerciseDiaries
where o.Date == date
select o).First();
var weight = (from o in dblists.Weights
where o.DiaryID == thediary.ID
select o).First();
var sets = (from x in dblists.Sets
where x.WeightId == weight.WeightID
select x).ToList();
}
return View(sets);
}
You should also wrap your LINQ to Entities data access in a using block so it's properly disposed of.
There's always many ways to do things, but... I think the easiest way would be to use First() since you are always just grabbing the first result in a list.
Another way to make it a little cleaner is to put your LINQ statements on multiple lines like I did for sets.
You can also use var, which some people like and others don't to have the compiler infer the type. I did this with sets below. I feel it cleans up the code a bit when you have large declarations with IEnumerable and generics.
public ActionResult showDiary(string datein)
{
LocalTestEntities1 dblists = new LocalTestEntities1();
DateTime date = Convert.ToDateTime(datein);
ExerciseDiary thediary = dblists.ExerciseDiaries.First(o => o.Date == date);
Weight weight = dblists.Weights.First(o.DiaryID == thediary.ID);
var sets = from x in dblists.Sets
where x.WeightId == weight.WeightID
select x;
return View(sets);
}
IMO this is easier to read than what you had in your answer above.
Be careful using First() because it will throw an exception if there are no records.
public ActionResult showDiary(string datein)
{
using( var dblists = new LocalTestEntities1())
{
var date = Convert.ToDateTime(datein);
var thediary = dblists.ExerciseDiaries.First(o => o.Date == date);
var weight = dblists.Weights.First(o => o.DiaryID ==thediary.ID);
var sets = dblists.Sets.Where(x => x.WeightId == weight.WeightID).AsEnumerable();
return View(sets);
}
}
Warning: If it's possible the data wont always be there. Use FirstOrDefault instead and check for null values.
I have a simple database with two tables. Users and Configurations. A user has a foreign key to link it to a particular configuration.
I am having a strange problem where the following query always causes an inner join to the Configuration table regardless of the second parameter value. As far as I can tell, even though the "UserConfiguration =" part of the object initialisation is conditional, LINQ doesn't see that and determines that a relationship is followed in any case.
If I actually remove that last initialisation, the whole thing works as expected. It doesn't inner join when loadConfiguration == false and it does join when loadConfiguration == true.
Anyone got any ideas about this? Is this syntax just not going to work? The only thought I have now is to wrap the return in a basic if statement - I just wanted to avoid the duplicated lines.
public UserAccount GetByUsername(string username, bool loadConfiguration)
{
using (Database database = new Database())
{
if (loadConfiguration)
{
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<User>(c => c.Configuration);
database.LoadOptions = loadOptions;
}
return (from c in database.Users
where c.Username == username
select new UserAccount
{
ID = c.ID,
ConfigurationID = c.ConfigurationID,
Username = c.Username,
Password = c.Password.ToArray(),
HashSalt = c.HashSalt,
FirstName = c.FirstName,
LastName = c.LastName,
EmailAddress = c.EmailAddress,
UserConfiguration = (loadConfiguration) ? new ApplicationConfiguration
{
ID = c.Configuration.ID,
MonthlyAccountPrice = c.Configuration.MonthlyAccountPrice,
TrialAccountDays = c.Configuration.TrialAccountDays,
VAT = c.Configuration.VAT,
DateCreated = c.Configuration.DateCreated
} : null
}).Single();
}
}
Thanks in advance,
Martin.
I dont think it will work like that.
I suggest splitting it into 2 distinct queries.
There are probably better ways, but it would require more 'plumbling'.
Nope, this will not work. I've run into similar issues many times. The reason for that has to do with expressions at compile time vs. conditions at run-time.
You could do 2 queries or if you don't mind joining to configuration regardless of loadConfiguration parameter, you could use:
var q = (from c in database.Users
where c.Username == username
select c).Single();
and then use Linq-to-Objects on the result.
Replace .Single() with SingleOrDefault() and Linq will switch to a left outer join. I don't know if in your case it will do it, but in some cases it does.
Edit dint's see the Single was for the entire query and not for the configuration part:
try this:
UserConfiguration = (loadConfiguration && c.Configuration != null) ? new ApplicationConfiguration
{
ID = c.Configuration.ID,
MonthlyAccountPrice = c.Configuration.MonthlyAccountPrice,
TrialAccountDays = c.Configuration.TrialAccountDays,
VAT = c.Configuration.VAT,
DateCreated = c.Configuration.DateCreated
} : null