How to do an OR in LINQ from statement - linq

I am trying to write a LINQ query where I want to access data from two different tables depending on what the front end sends back
if FlowerClients is being sent from the front end, I want to use FlowerClient table OR if data being sent is for AnotherClient use AnotherClient.
Is this possible to do in LINQ or is it better to create different methods?
var flowerById = (from flower in flowerContext.Flowers
where flower.FlowerId == flowerId
join petals in flowerContext.Petals on flower.PetalId equals petals.PetalId
from flowerClients in flowerContext.FlowerClients.Where(x => x.FlowerId == flower.FlowerId).DefaultIfEmpty()
||
from anotherFlowerClients in flowerContext.AnotherClients.Where(x => x.FlowerId == flower.FlowerId).DefaultIfEmpty()

You'll probably want to create different methods, particularly if the FlowerClients and AnotherClients classes are very different.
Otherwise, you could dynamically generate your query expression. You will probably want to make sure that FlowerClients and AnotherClients implement a common interface however that way you don't have to do any sort of mapping between the two.
IQueryable<FlowerPetal> query1 = flowerContext.Flowers
.Where(f => f.FlowerId == flowerId)
.Join(flowerContext.Petals,
f => f.PetalId,
p => p.PetalId,
(f, p) => new FlowerPetal { Flower = f, Petal = p }
);
IQueryable<FlowerPetalClient> WithClients(IQueryable<FlowerPetal> _query, IQueryable<IClient> _clients) =>
_query.SelectMany(
x => _clients.Where(c => c.FlowerId == x.Flower.FlowerId).DefaultIfEmpty(),
(x, c) => new FlowerPetalClient { Flower = x.Flower, Petal = x.Petal, Client = c }
);
IQueryable<IClient> clients = useFlowerClients // decide on which client to use
? flowerContext.FlowerClients
: flowerContext.AnotherClients;
var query = WithClients(query1, clients); // expand on query
with some helper classes:
class FlowerPetal
{
public Flower Flower { get; set; }
public Petal Petal { get; set; }
}
class FlowerPetalClient
{
public Flower Flower { get; set; }
public Petal Petal { get; set; }
public IClient Client { get; set; }
}

Related

LINQ Lazy load or query incorrect

LINQ Query not populating
Model extract is as follows
public class ServiceBulletin
{
[Key]
public int Id { get; set; }
public virtual ICollection<ServiceBulletinProducts> ApplicableProducts { get; set; }
}
public class ServiceBulletinProducts
{
[Key]
public int Id { get; set; }
public int ServiceBulletinId { get; set; }
public virtual Product Product{ get; set; }
}
I'm using the following code at the moment to populate a collection
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts)
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;
var x1 = new List<ServiceBulletin>();
foreach (var item in x)
{
var p = from m1 in _dc.ServiceBulletinsProducts.Include(p2=>p2.Product)
where m1.Product.DeleteStatus == DeleteStatus.Active &&
m1.ServiceBulletinId == item.Id
select m1;
var p99 = p.ToList();
item.ApplicableProducts = p99;
x1.Add(item);
};
So this is intended to have a Parent Child relationship and I’m trying to do a query which populates a collection of ServiceBulletins with a ApplicableProducts item with a fully populated collection of ServiceBulletinProducts for the ServiceBulletin with the values of the Product populated
The collection is populated but the ServiceBulletinProducts are always set to null and I can’t seem to add an Include such as .Include(p => p.ApplicableProducts.Products) to try and populate the product details – which is resulting in me iterating around the collection to populate the items.
Am I missing something to enable the population on the 1st query for the Include statement or do I need to do the query in a different way ?
Figured out the following should do the trick.
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts.Select(p2=>p2.Product))
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;

LINQ Query to join three tables

I need a help in LINQ Query for the below.
public interface IBrand
{
int BrandId { get; set; }
IEnumerable<IBuyingAgency> BuyingAgencies { get; set; }
}
public interface IBuyingAgency
{
int BuyingAgencyId { get; set; }
}
public interface IClientGroup
{
IBuyingAgency BuyingAgency { get; set; }
int ClientGroupId { get; set; }
}
1). var brands = LoggedInUserHelper.GetUser().GetBrands(roles); // returns IEnumerable<Tuple<IBrand, string>>
2). var buyingAgencies = LoggedInUserHelper.GetUser().GetBuyingAgencies(roles); //IEnumerable<IBuyingAgency>
3). var clientGroups = LoggedInUserHelper.GetUser().GetClientGroups(roles); //IEnumerable<IClientGroup>
function IEnumerable<IClientGroup> GetClientGroups( List<int> BrandIds)
{
var brands = LoggedInUserHelper.GetUser().GetBrands(roles); // returns IEnumerable<Tuple<IBrand, string>>
var buyingAgencies = LoggedInUserHelper.GetUser().GetBuyingAgencies(roles); //IEnumerable<IBuyingAgency>
var clientGroups = LoggedInUserHelper.GetUser().GetClientGroups(roles); //IEnumerable<IClientGroup>
var lstBrandagencies = brands.Where(brand => BrandIds.Contains(brand.Item1.BrandId) && brand.Item1.BuyingAgencies.Any( ba => buyingAgencies.Contains(ba.BuyingAgencyId))).SelectMany(brand => brand.Item1.BuyingAgencies);
var buyingAgencyIDs = lstBrandagencies.Select(b => b.BuyingAgencyId);
clientGroups = clientGroups.Where(cg => buyingAgencyIDs.Contains(cg.BuyingAgency.BuyingAgencyId));
return Mapper.Map<IEnumerable<IClientGroup>>(clientGroups.ToList());
}
I wrote the above function but not working, it gets all the clientgroups instead of filtering
I wants to write a query to get all ClientGroups whch satisfies the below condition
1. retrieve the brand from brands ( above ) that matches the list of brandId's passing in as parameter
2. Than get all the buyingAgencies under brands (1) above which matches with the id's of (2) above
3. Finally get all clientgroups which matches with the buyingAgency retrieving in step (2)
Please can you help.
you are not filtering from your source 2) in this line
var buyingAgencyIDs = lstBrandagencies.Select(b => b.BuyingAgencyId);
just projecting from the previous query.
If I understood correctly you want to do this.
var lstBrandagencies = (from a in brands
where BrandIds.Contains(a.Item1.BrandId )
select a).SelectMany (b => b.Item1.BuyingAgencies )
.Select (b => b.BuyingAgencyId );
var buyingAgencyIDs = from a in buyingAgencies
where lstBrandagencies.Contains(a.BuyingAgencyId )
select a.BuyingAgencyId;
var clientGroupsResult = clientGroups.Where(cg => buyingAgencyIDs.Contains(cg.BuyingAgency.BuyingAgencyId));

Join Lambda Expression

im just trying to make a join from two entities.
the two entieties are as folows:
public partial class AnswerSet
{
public int Id { get; set; }
public string Ans { get; set; }
public bool IsTrue { get; set; }
public int QuestionId { get; set; }
public virtual QuestionSet QuestionSet { get; set; }
}
and
public partial class QuestionSet
{
public QuestionSet()
{
this.AnswerSets = new HashSet<AnswerSet>();
}
public int Id { get; set; }
public string Quest { get; set; }
public virtual ICollection<AnswerSet> AnswerSets { get; set; }
}
So, there are a question and an Answer Entity on the database. 1 Question has more answers (in my example 4). So now im tried this:
var v1 = db.QuestionSets
.Select(q => q)
.Where(q=> q.Id == 11)
.Join(db.AnswerSets,
q => q.Id,
a => a.QuestionId,
(a, q) => new { question = q });
So, now i have the following output when the expression is as above (see image 1):
Here i have just the Answers.
when i chage the expression to:
var v1 = db.QuestionSets
.Select(q => q)
.Where(q=> q.Id == 11)
.Join(db.AnswerSets,
q => q.Id,
a => a.QuestionId,
(q, a) => new { question = q });
then i have the following output (see image 2): (just the question, but 4 times. as many answers i have.)
So my question is, how can i join these two entities, that the Answers are a set in the QuestionSet entity?
thank you
Image 1
Image 2
You want a group join (see http://msdn.microsoft.com/en-us/library/bb311040.aspx)
var QAs =
from q in db.QuestionSets
join a in db.AnswerSets
on q.Id equals a.QuestionId into answers
select new { Question = q, Answers = answers };
In Extension Method syntax:
var QAs = db.QuestionSets
.GroupJoin(
db.AnswerSets,
q => q.Id,
a => a.QuestionId,
(q, answers) => new {Question = q, Answers = answers});
Hope that helps
PS. Use it like so:
foreach (var qa in QAs)
{
Console.WriteLine("Question #{0} has {1} answers",
qa.Question.Id, qa.Answers.Count());
}
What about leaving the Join technique for complex query and use Ef Eager Loading by using Include
var v1 = db.QuestionSets.Include(b = b.Answer);
or
var v1 = db.QuestionSets.Include("Answer");

Lambda statement to project results based on if

I have a user who is part of a company, this company can have multiple offices, so the user can be part of head/main office or part of another office, I am projecting from a lamdba expression but I cannot figure out how to do: if user is not headoffice throw out the office address.
The code below shows user, joined onto userhistory (2 table join - which is necessary so I can throw out some info that is held on that table related to this user), here is what I have done so far:
[HttpPost]
[AjaxOnly]
public PartialViewResult GetUsers(string term)
{
var _sf = _repo.Single<Company>(x => x.Type == x.IsActive &&
(x.Identifier.Contains(term) || x.Name.Contains(term)));
//get company with addresses...
var users = _repo.All<User>().Where(x => x.CompanyID == _sf.CompanyID);
var offices = _repo.All<Office>().Where(x => x.CompanyID == _sf.CompanyID);
var _users = _repo.All<UserHistory>()
.Join(users, x => x.UserID, y => y.UserID,
(s, u) => new
{
_s = s,
_user = u
}).Select(x => new QuoteData
{
Login = x._user.Login,
Name = string.Format("{0} {1}", x._user.FirstName, x._user.LastName),
Tel = x._s.Mobile,
//let me know where user is based, if head office get me the address too...
IsBasedInHeadOffice = x._user.IsBasedInHeadOffice
//here: if !IsBasedInHeadOffice => GetMeAddress
});
return PartialView("QuoteUsersUC", _users);
}
public class QuoteData
{
public string Login { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Tel { get; set; }
public bool IsBasedInHeadOffice { get; set; }
}
Could I have written this even better/ simpler?
You can do it like this:
.Select(x =>
{
var result = new QuoteData
{
Login = x._user.Login,
Name = string.Format("{0} {1}", x._user.FirstName,
x._user.LastName),
Tel = x._surveyor.Mobile,
IsBasedInHeadOffice = x._user.IsBasedInHeadOffice
};
if(!result.IsBasedInHeadOffice)
result.Address = GetMeAddress();
return result;
});
UPDATE:
Using LINQ2SQL or EF, this should be a lot simpler because of the so called navigation properties. Basically, they remove the need for manual joins in your C# code, if your database is properly set up with foreign keys.
For example, if your table USER_HISTORY would have a foreign key constraint on the column user_id to the table USER, your class User would have a property UserHistories of type IEnumerable<UserHistory> that contains all associated user histories and the class UserHistory would have a property User. The same is true for all other associations: User <-> Company and Company <-> Office
Using this, your code could easily be rewritten to this:
public PartialViewResult GetUsers(string term)
{
var sf = _repo.Single<Company>(x => x.Type == x.IsActive &&
(x.Identifier.Contains(term) || x.Name.Contains(term)));
var users =
sf.Users
.SelectMany(x => x.UserHistories
.Select(y =>
new QuoteData
{
Login = x.Login,
Name = string.Format("{0} {1}",
x.FirstName,
x.LastName),
Tel = y.Mobile,
IsBasedInHeadOffice = x.IsBasedInHeadOffice
Address = x.IsBasedInHeadOffice ?
sf.Office.Address :
string.Empty
}));
return PartialView("QuoteUsersUC", _users);
}

Why predicate isn't filtering when building it via reflection

I'm building a rather large filter based on an SearchObject that has 50+ fields that can be searched.
Rather than building my where clause for each one of these individually I thought I'd use some slight of hand and try building custom attribute suppling the necessary information and then using reflection to build out each of my predicate statements (Using LinqKit btw). Trouble is, that the code finds the appropriate values in the reflection code and successfully builds a predicate for the property, but the "where" doesn't seem to actually generate and my query always returns 0 records.
The attribute is simple:
[AttributeUsage(AttributeTargets.Property, AllowMultiple=true)]
public class FilterAttribute: Attribute
{
public FilterType FilterType { get; set; } //enum{ Object, Database}
public string FilterPath { get; set; }
//var predicate = PredicateBuilder.False<Metadata>();
}
And this is my method that builds out the query:
public List<ETracker.Objects.Item> Search(Search SearchObject, int Page, int PageSize)
{
var predicate = PredicateBuilder.False<ETracker.Objects.Item>();
Type t = typeof(Search);
IEnumerable<PropertyInfo> pi = t.GetProperties();
string title = string.Empty;
foreach (var property in pi)
{
if (Attribute.IsDefined(property, typeof(FilterAttribute)))
{
var attrs = property.GetCustomAttributes(typeof(FilterAttribute),true);
var value = property.GetValue(SearchObject, null);
if (property.Name == "Title")
title = (string)value;
predicate.Or(a => GetPropertyVal(a, ((FilterAttribute)attrs[0]).FilterPath) == value);
}
}
var res = dataContext.GetAllItems().Take(1000)
.Where(a => SearchObject.Subcategories.Select(b => b.ID).ToArray().Contains(a.SubCategory.ID))
.Where(predicate);
return res.ToList();
}
The SearchObject is quite simple:
public class Search
{
public List<Item> Items { get; set; }
[Filter(FilterType = FilterType.Object, FilterPath = "Title")]
public string Title { get; set; }
...
}
Any suggestions will be greatly appreciated. I may well be going way the wrong direction and will take no offense if someone has a better alternative (or at least one that works)
You're not assigning your predicate anywhere. Change the line to this:
predicate = predicate.Or(a => GetPropertyVal(a, ((FilterAttribute)attrs[0]).FilterPath) == value);

Resources