Whether I should write, simple join for common records? - asp.net-mvc

I am developing an ASP.NET MVC application. I have two queries I want to get common records from those queries.
Am I suppose to write simple join to get the common records ?
var poList =
(from po in db.PurchaseOrders
where po.CompanyId == companyId &&
po.PartyId == partyId &&
(po.IsDeleted == false || po.IsDeleted == null)
select po into newPO
select new
{
Name = newPO.PONo,
Id = newPO.Id
});
var poList2 = (db.Employees.Where(x => x.Id == EmpID)
.SelectMany(x => x.Roles)
.SelectMany(x => x.Employees)
.Distinct()
.SelectMany(x => x.PurchaseOrders)
.Select(po => new { Name = po.PONo, Id = po.Id }));
I am trying to write the join but its asking for one more argument, how to write a simple join for common records ?
var finalPO = poList.Join(poList2).ToList();

You can use an overload of Join method to specify join conditions:
poList.Join(poList2, a => a.Name, b => b.Name, (a,b) => new { Name = b.PONo, Id = b.Id });

Union will give you all records from both:
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.union.aspx
Join method will give you records that match on provided key, but requires more than just the two enumerables as parameters:
http://msdn.microsoft.com/en-us/library/bb534675.aspx

You don't need a join because you can apply the expressions in the first query to the "raw" result of the second one:
var poList2 = db.Employees.Where(x => x.Id == EmpID)
.SelectMany(x => x.Roles)
.SelectMany(x => x.Employees)
.Distinct()
.SelectMany(x => x.PurchaseOrders);
var result = from po in poList2
where po.CompanyId == companyId &&
po.PartyId == partyId &&
!po.IsDeleted
select po into newPO
select new
{
Name = newPO.PONo,
Id = newPO.Id
};
And if you need the result you originally intended to get from poList2:
var result2 = poList2.Select(po =>
{
Name = po.PONo,
Id = po.Id
};
So, generally speaking, you can do more with your query bodies if you postpone the projection to anonymous types.
Side note: I used !po.IsDeleted because I'd strongly recommend to make the field not nullable, with false as default value.

Related

Orderby clause not working with drop down list in mvc

I am populating a drop down list using Linq and the orderby clause doesn't seem to work.
public List<Hello> getManagers()
{
var que = (from man in db.Table1
where man.Role == "Manager"
orderby man.Name
select new Hello
{
Managers = man.Name
}).Distinct().ToList();
return que;
}
Controller Class:
public ActionResult Index()
{
rp = new RequestProcess();
ViewBag.ID = fillSelectedList("", "ID", rp);
ViewBag.Managers = fillSelectedList("", "Managers", rp);
return View(""); //View 1
}
public static List<SelectListItem> fillSelectedList(string selValue, string type, RequestProcess rp )
{
List<SelectListItem> list = new List<SelectListItem>();
SelectListItem obj = new SelectListItem();
if (type == "Managers") {
var tempList= rp.getManagers();
tempList.ForEach(x =>
{
obj = new SelectListItem();
obj.Text = x.Managers;
obj.Value = x.Managers;
obj.Selected = x.Managers == selValue ? true : false;
list.Add(obj);
});
}
return list;
}
I am still receiving an un-ordered list. Any fixes?
The result is not ordered, because method Distinct does not return ordered results. What you need to do instead is to first call Disctinct, and only then OrderBy:
var que = (from man in db.Table1
where man.Role == "Manager"
select new Hello
{
Managers = man.Name
}).Distinct() // <- First distinct ...
.OrderBy(x => x.Managers) // <- ... then order by
.ToList();
As mentioned in the answer above, you need to sort the result after Distinct().
Also note that you are mixing Lambda expression and LINQ to Entities Queries... you may want to consider choosing one of them for consistency (though there is no syntax error if you mix them). This is the same query using lambda expression:
var que = _context.Table1
.Where(m => m.Role == "Manager")
.Select(h => new Hello { Managers = h.Name })
.Distinct()
.OrderBy(o => o.Managers)
.ToList();

how to handle null value in many to many relationship

I am trying to achieve something like this:
if there is a matching id then filter result according to it otherwise bypass the condition
.Where(x => x.NeighbourhoodId == (id ?? x.NeighbourhoodId)
but i am not getting correct syntax with many to many relationship:
public JsonResult GetPost(int? id, int? tagid)
{
var ret = from data in db.Posts.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.OrderByDescending(x => x.PostedDate)
.Where(x => x.NeighbourhoodId == (id ?? x.NeighbourhoodId)
&& x.Tags.Any(t => t.TagId == tagid))
.ToList()
select new
{
TagName = string.Join(",", data.Tags.Select(t => t.TagName)),
Message = data.Message,
// and other related stuff
}
here, as u can see,this where clause contains multiple conditions i want to filter post.There will be only one parameter with value. means if id parameter have value then tagid will be null and if tagid is null then id would have some value.
now, i want if there is null value in tagid then still this query should run. right now, its not working becoz in database, there is no post with empty tagid or null .how to do it. any suggestions??
If I understand correctly, you need to build the filter dynamically based on the passed parameters like this
var posts = db.Posts
.Include(x => x.Tags)
.Include(x => x.Neighbourhood)
.OrderByDescending(x => x.PostedDate);
if (id != null)
posts = posts.Where(x => x.NeighbourhoodId == id.Value);
if (tagid != null)
posts = posts.Where(x => x.Tags.Any(t => t.TagId == tagid.Value));
var ret = from data in posts
// ... the rest

how to apply inner join in entityframework LINQ method syntax?

How to apply this query in entity framework method syntax
select company_id, country_id from companies, departments where companies.company_id == departments.company_id and department.departmentId = 10;
So far, I have:
var company = context.companies
.Where(com => com.Departments
.Contains(context.departments
.Where(dep => dep.department_id==_user.Department)
.FirstOrDefault()
)
)
.Select(com => new { com.company_id, com.Country })
.FirstOrDefault();
Using method based syntax, this could be as simple as;
var company = context.Companies
.Where(x => x.Departments
.Any(x => x.department_id == _user.Department)
)
.Select(x => new { x.company_id, x.Country });
This assumes your tables are set up with foreign keys giving each Company a list of Department objects. It very much depends on your data structure.

How do I get this ViewModel correct?

Utilizing MVC 5 and Entity Framework I am trying to set up my a ViewModel for my Index view for a show of Employees and their goals.
I have an employee table, an employeeMap table (join table with payload) and a goal table.
There is a one-to-many relationship between Employee and EmployeeMap and between Goal and EmployeeMap.
I am a total newbie and getting stuck with an index view, which initially should display employees, and when one employee is selected should display the goals of the employees.
I can't get my index action right:
var viewModel = new EmployeeGoals();
viewModel.Employees = db.Employees
.Include(d => d.Department)
.Include(e => e.Position)
.Include(m => m.EmployeeMaps)
.Where(d => d.OrganizationID == oid && d.Department.ManagerID == currentUser.EmployeeID)
.OrderBy(d => d.HireDate);
if (id != null)
{
ViewBag.EmployeeID = id.Value;
viewModel.EmployeeMaps = viewModel.Employees.Where(e => e.ID == id.Value).Single().EmployeeMaps;
viewModel.Goals = viewModel.EmployeeMaps.Where(e => e.EmployeeID == ViewBag.EmployeeID).Select(e => e.Goals);
}
if (goalID != null)
{
ViewBag.GoalID = goalID.Value;
viewModel.Activities = viewModel.Goals.Where(
x => x.ID == goalID).Single().Activities;
}
return View(viewModel);
I do get the viewmodel.employees populated correctly, but not the viewmodel.goals
oh, and the viewmodel is:
public class EmployeeGoals
{
public IEnumerable<EmployeeMap> EmployeeMaps { get; set; }
public IEnumerable<Employee> Employees { get; set; }
public IEnumerable<Goal> Goals { get; set; }
}
A hint to help me past this would be great.
Thanks
Got it working using a different approach:
viewModel.Employees = db.Employees
.Include(d => d.Department)
.Include(e => e.Position)
.Include(m => m.EmployeeMaps)
.Where(d => d.OrganizationID == oid && d.Department.ManagerID == currentUser.EmployeeID)
.OrderBy(d => d.HireDate);
if (id != null)
{
ViewBag.EmployeeID = id.Value;
viewModel.EmployeeMaps = viewModel.Employees.Where(e => e.ID == id.Value).Single().EmployeeMaps;
viewModel.Goals = from g in db.Goals
join m in db.EmployeeMaps on g.ID equals m.GoalID
join e in db.Employees on m.EmployeeID equals e.ID
where m.EmployeeID == id.Value
select g;
}
couldn't figure out how to get a result using navigation properties, so ended up with above solution. It does the job, but am I hitting the database too often?? Also, ended up with a mix of LINQ syntax'es - should go with just one of them, I know :-/
You should use SelectMany:
viewModel.Goals = viewModel.EmployeeMaps
.Where(e => e.EmployeeID == ViewBag.EmployeeID)
.SelectMany(e => e.Goals);
because EmployeeMaps.Where() is an IEnumerable, so a Select produces IEnumerable<IEnumerable<Goal>>. SelectMany flattens this into IEnumerable<Goal>.

Problems adding new property to existing node with Neo4jClient

My beginner problems with using Neo4jClient unfortunately continues :) I have a simple class WorkEntity for which I have an update query:
public class WorkEntity
{
public string Id { get; set; }
public string Description { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}
var query = graphClient.Cypher
.Match("(work:Work)", "(city:City)", "(profession:Profession)", "(company:Company)", "(oldCompany:Company)", "(oldProfession:Profession)", "(oldCity:City)",
"(user:User)-[r1]->work", "work-[r2]->oldProfession", "work-[r3]->oldCompany", "work-[r4]->oldCity")
.Where((WorkEntity work) => work.Id == model.Id)
.AndWhere((CityEntity city) => city.Id == model.CityId)
.AndWhere((CityEntity oldCity) => oldCity.Id == oldModel.CityId)
.AndWhere((ProfessionEntity profession) => profession.Id == model.ProfessionId)
.AndWhere((ProfessionEntity oldProfession) => oldProfession.Id == oldModel.ProfessionId)
.AndWhere((CompanyEntity company) => company.Id == model.CompanyId)
.AndWhere((CompanyEntity oldCompany) => oldCompany.Id == oldModel.CompanyId)
.AndWhere("type(r1) = 'CURRENT'")
.AndWhere("type(r2) = 'WORK_AS_PROFESSION'")
.AndWhere("type(r3) = 'WORK_AT_COMPANY'")
.AndWhere("type(r4) = 'WORK_IN_CITY'")
.Set("work = {updatedWork}")
.WithParam("updatedWork", updatedEntity);
//If Date has been set delete current relationships
if (oldModel.EndDate == DateTime.MinValue && model.EndDate > DateTime.MinValue)
{
query = query.Delete("r1");
}
if (oldModel.ProfessionId != model.ProfessionId)
{
query = query.Delete("r2")
.CreateUnique("work-[:WORK_AS_PROFESSION]->profession");
}
if (oldModel.CompanyId != model.CompanyId)
{
query = query.Delete("r3")
.CreateUnique("work-[:WORK_AT_COMPANY]->company");
}
if (oldModel.CityId != model.CityId)
{
query = query.Delete("r4")
.CreateUnique("work-[:WORK_IN_CITY]->city");
}
query.ExecuteWithoutResults();
Modifying all the relationsships works as expected but if for example Description is null from the beginning above query won't add Description to an existing entity (or update any other of the properties) even though it is set in updatedEntity. If I simplify the query as below Description is added/removed and existing changed properties are updated correctly. How can that be? I really would prefer to do the whole query in one transaction.
var query = graphClient.Cypher
.Match("(work:Work)")
.Where((WorkEntity work) => work.Id == model.Id)
.Set("work = {updatedWork}")
.WithParam("updatedWork", updatedEntity);
I think the reason the query does nothing when the CityIds are the same in my gist is because the MATCH clause:
work-[r4]-oldCity
is not matching anything, so the match fails and the query does nothing.
In effect - if I get this right - you're attempting two queries:
Update work
Delete & Create new relationships
I think you should check out the WITH keyword, as it should help your query...
WITH allows you to chain your cypher queries together, so you could change your query to:
var query = Client.Cypher
.Match("(work:Work)")
.Where((WorkEntity work) => work.Id == model.Id)
.Set("work = {updatedWork}")
.With("work")
.Match("(city:City)", "(profession:Profession)", "(company:Company)", "(oldCompany:Company)", "(oldProfession:Profession)", "(oldCity:City)",
"(user:User)-[r1]->work", "work-[r2]->oldProfession", "work-[r3]->oldCompany", "work-[r4]->oldCity")
.Where((WorkEntity work) => work.Id == model.Id)
.AndWhere((CityEntity city) => city.Id == model.CityId)
.AndWhere((CityEntity oldCity) => oldCity.Id == oldModel.CityId)
.AndWhere((ProfessionEntity profession) => profession.Id == model.ProfessionId)
.AndWhere((ProfessionEntity oldProfession) => oldProfession.Id == oldModel.ProfessionId)
.AndWhere((CompanyEntity company) => company.Id == model.CompanyId)
.AndWhere((CompanyEntity oldCompany) => oldCompany.Id == oldModel.CompanyId)
.AndWhere("type(r1) = 'CURRENT'")
.AndWhere("type(r2) = 'WORK_AS_PROFESSION'")
.AndWhere("type(r3) = 'WORK_AT_COMPANY'")
.AndWhere("type(r4) = 'WORK_IN_CITY'")
.WithParam("updatedWork", updatedEntity);
This will execute the update and then the rest.
Another keyword that might be worth a look would be MERGE but I think WITH should help you out here.
Thanks Chris, I realise that my understanding for Neo4j is still quite limited :) Your suggestion above updates the work entity properties correctly but not the relationsships. I don't really get why the work-[r4]-oldCity relationship doesn't match anything but anyway I took advantage of your note about this and after some trial and error finally got the query to work correctly like:
var oldModel = GetWorkModel(model.Id);
var updatedEntity = Mapper.Map<WorkEntity>(model);
var query = graphClient.Cypher
.Match("(work:Work)", "(city:City)", "(profession:Profession)", "(company:Company)",
"(user:User)-[r1:CURRENT]->work", "work-[r2:WORK_AS_PROFESSION]->()", "work-[r3:WORK_AT_COMPANY]->()", "work-[r4:WORK_IN_CITY]->()")
.Where((WorkEntity work) => work.Id == model.Id)
.AndWhere((CityEntity city) => city.Id == model.CityId)
.AndWhere((ProfessionEntity profession) => profession.Id == model.ProfessionId)
.AndWhere((CompanyEntity company) => company.Id == model.CompanyId)
.Set("work = {updatedWork}")
.WithParam("updatedWork", updatedEntity);
if (oldModel.EndDate == DateTime.MinValue && model.EndDate > DateTime.MinValue)
query = query.Delete("r1");
if (oldModel.ProfessionId != model.ProfessionId)
query = query.Delete("r2").CreateUnique("work-[:WORK_AS_PROFESSION]->profession");
if (oldModel.CompanyId != model.CompanyId)
query = query.Delete("r3").CreateUnique("work-[:WORK_AT_COMPANY]->company");
if (oldModel.CityId != model.CityId)
query = query.Delete("r4").CreateUnique("work-[:WORK_IN_CITY]->city");
query.ExecuteWithoutResults();

Resources