LINQ Join and GroupJoin - linq

I have a list of objects, those objects may or may not have contact info:
// Join contact
query = query.Join(
(new ContactRepository(this.Db)).List().Where(x => x.IsMainContact),
x => new { x.ListItem.ContentObject.LoginId },
y => new { y.LoginId },
(x, y) => new ListItemExtended<ListItemFirm>
{
City = y.City,
State = y.State,
Country = y.Country
});
This does inner join on 'LoginId'. But I need an outter join so that if contact info does not exists for a given LoginId it will be empty.
Please help
thanks

You should execute outer join manually:
var contacts = (new ContactRepository(this.Db)).List();
query.Select(item =>
{
var foundContact = contacts.FirstOrDefault(contact => contact.Id == item.Id);
return new ListItemExtended<ListItemFirm>()
{
Id = item.Id,
City = foundContact != null ? foundContact.City : null,
State = foundContact != null ? foundContact.State : null,
Country = foundContact != null ? foundContact.Country : null,
};
})
But remember that if your Contact item is struct - checking for null isn't proper way. Use Any() operator instead of FirstOrDefault().

Related

LinqToDB Exception cannot be converted to SQL

Hello I have an issue with this query
var queryGrouped = queryFiltered
.GroupBy(c => new { c.Id, c.TableOneId, c.TableOneName, c.TableTwoId, c.TableTwoName, c.TableTwoCode, c.TableThreeId, c.TableThreeName, c.Description, c.EffectiveDate, c.CreatedBy, c.ServiceGroupName })
.DisableGuard()
.Select(cg => new Model
{
Id = cg.Key.Id,
TableOneId = cg.Key.TableOneId,
TableOneName = cg.Key.TableOneName,
TableTwoId = cg.Key.TableTwoId,
TableTwoCode = cg.Key.TableTwoCode,
TableTwoName = cg.Key.TableTwoName,
TableThreeId = cg.Key.TableThreeId,
TableThreeName = cg.Key.TableThreeName,
Description = cg.Key.Description,
EffectiveDate = cg.Key.EffectiveDate,
EffectiveDateText = cg.Key.EffectiveDate != null ? cg.Key.EffectiveDate.Value.ToString("MM/dd/yyyy") : string.Empty,
ServiceGroupName = string.Join(", ", cg.Select(g => g.ServiceGroupName).Distinct()),
CreatedBy = cg.Key.CreatedBy
}).OrderBy(x => x.ServiceGroupName).ToListAsync();
If i run this when try to order by the field ServiceGroup it returns this message
LinqToDB.Linq.LinqException: ''Join(", ", cg.Select(g => g.ServiceGroupName).Distinct())' cannot be converted to SQL.'
So I don't know how to order by this field ServiceGroupName, thanks for any answer.
I would suggest to make grouping on the client side. Note that I have removed ServiceGroupName from grouping key.
var data = await queryFiltered
.Select(c => new {
c.Id,
c.TableOneId,
c.TableOneName,
c.TableTwoId,
c.TableTwoName,
c.TableTwoCode,
c.TableThreeId,
c.TableThreeName,
c.Description,
c.EffectiveDate,
c.CreatedBy,
c.ServiceGroupName
})
.ToListAsync();
var queryGrouped = data
.GroupBy(c => new { c.Id, c.TableOneId, c.TableOneName, c.TableTwoId, c.TableTwoName, c.TableTwoCode, c.TableThreeId, c.TableThreeName, c.Description, c.EffectiveDate, c.CreatedBy })
.Select(cg => new Model
{
Id = cg.Key.Id,
TableOneId = cg.Key.TableOneId,
TableOneName = cg.Key.TableOneName,
TableTwoId = cg.Key.TableTwoId,
TableTwoCode = cg.Key.TableTwoCode,
TableTwoName = cg.Key.TableTwoName,
TableThreeId = cg.Key.TableThreeId,
TableThreeName = cg.Key.TableThreeName,
Description = cg.Key.Description,
EffectiveDate = cg.Key.EffectiveDate,
EffectiveDateText = cg.Key.EffectiveDate != null ? cg.Key.EffectiveDate.Value.ToString("MM/dd/yyyy") : string.Empty,
ServiceGroupName = string.Join(", ", cg.Select(g => g.ServiceGroupName).Distinct()),
CreatedBy = cg.Key.CreatedBy
})
.OrderBy(x => x.ServiceGroupName)
.ToList();

Dynamic where clause with two entity

I need a filter between two entity.
Have two tables 1.User 2.Product
Product map with the User table.
I am going to create a dynamic where filter.
I need to find out all the users which have 'test' product.
Conditions: if userFilter count is 0 then I need all test product with the respected user.
If userFilter is there and productFilter is there then below code is working but if userFilter is not there and productFilter is there then it returning 0 row. How can I find the users which have test product? ?
Here is my Code.
public IHttpActionResult GetFilter()
{
var userFilters = new List<Filter>()
{
new Filter { PropertyName = "Username" ,
Operation = Op .Equals, Value = "Karan" },
};
var productfilter = new List<Filter>()
{
new Filter { PropertyName = "Name" ,
Operation = Op .Equals, Value = "Test product" }
};
Func<User, bool> deleg = x => true;
Func<Product, bool> delegProduct = x => true;
if (userFilters.Count > 0)
{
deleg = ExpressionBuilder.GetExpression<User>(userFilters).Compile();
}
if (productfilter.Count > 0)
{
delegProduct = ExpressionBuilder.GetExpression<Product>(productfilter).Compile();
}
var resultt = _localmarketEntities.Users.Where(deleg)
.Select(x => new
{
x.Id,
x.Username,
Product = x.Products.Where(delegProduct).Select(y => new
{
y.Id,
y.Name
}).ToList()
})
.ToList();
return Ok(resultt);
}
if i understand correct, you need all users that have test product when userFiler count is 0.
List<User> res;
var user = _localmarketEntities.Users.Where(deleg).ToList();
if (user.Count == 0) {
res = _localmarketEntities.Products.Where(delegProduct).Select(q => new User() {
Id = q.Id,
Username = q.Username,
Product = q
}).ToList();
}
else {
res = _localmarketEntities.Users.Where(deleg)
.Select(x => new
{
x.Id,
x.Username,
Product = x.Products.Where(delegProduct).Select(y => new
{
y.Id,
y.Name
}).ToList()
})
.ToList();
}

Linq - adding multiple different objects to a list

I am trying to add a range of values from four distinct list of objects to a list. This is the code I have to add all the items from one list of objects...
var formList = new List<FormList>();
formList = forms.LimitedWillForms.Select(a => new FormList()
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
}).ToList();
I am trying to not just add from the forms.LimitedWillForms list, but also from the forms.FullWillForms, and the forms.FullWillForms2, and the forms.FullWillForms3 too, adding the same parameters. This seems to work to add selected parameters from the form to the list.
I am not sure of the most efficient way to use linq to add selected parameters from all four lists to the formList. Can anyone help?
Since the lists contain objects of different types your best option would be to add an common interface to all the types for the common properties.
public interface IRecord
{
DateTime DateCreated {get;set;}
int FormId {get;set;}
....
}
You can then do:
var formList = forms.LimitedWillForms
.Cast<IRecord>
.Concat(forms.FullWillForms)
.Concat(forms.FullWillForms2)
.Concat(forms.FullWillForms3)
.Select(x => new FormList()
{
DateCreated = x.CreationDate,
FormId = x.Id,
FormType = x.FormType,
Submitted = x.SubmissionDate != null
}).ToList();
If you can live with just getting back a list if IRecord instead of FormList you can actually skip the last select.
If that is not possible you would need to select the properties from each collection.
var formList = forms.LimitedWillForms.Select(x => new FormList()
{
DateCreated = x.CreationDate,
FormId = x.Id,
FormType = x.FormType,
Submitted = x.SubmissionDate != null
}).Concat(
forms.FullWillForms.Select(x => new FormList()
{
DateCreated = x.CreationDate,
FormId = x.Id,
FormType = x.FormType,
Submitted = x.SubmissionDate != null
}
).Concat(...).ToList();
Try this:
var formList = forms.LimitedWillForms.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
})
.Union(forms.FullWillForms.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
}))
.Union(forms.FullWillForms2.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
}))
.Union(forms.FullWillForms3.Select(a => new FormList
{
DateCreated = a.CreationDate,
FormId = a.Id,
FormType = a.FormType,
Submitted = a.SubmissionDate != null
})).ToList();

How to create an identity column within a lambda?

How can I make the expression add a counter (ID) that is 1,2,3,4 etc... ? I just want to have some unqiue key to identify the data
var query = data.Select(x =>
new DemoItemV1
{
Id = x.Field<double>("ID"),
AreaId = x.Field<int>("1Area ID"),
CategoryTitle = x.Field<string>("2Table Title")
}).ToList();
I don't think you can do this purely in a Linq-to-Sql or Linq-to-Entities query. But, since you're already materializing it to a list, you can do this:
var query = data.Select(x =>
new DemoItemV1
{
AreaId = x.Field<int>("1Area ID"),
CategoryTitle = x.Field<string>("2Table Title")
})
.AsEnumerable()
.Select((x, i) => { x.ID = i + 1; return x })
.ToList();

LINQ lambda expression for many-to-one inner join involving max()

I have the following schema:
Table1
ID int
Table2
ID int
Table1ID int
Datetime datetime
Table3
ID int
Table2ID int
Name varchar(255)
All columns are not null. How do I write the following SQL query in LINQ using lambda expressions?
select Table1.*
from Table2
inner join (
select Table1ID, max(Datetime) as Datetime
from Table2
group by Table1ID
) a on Table2.Table1ID = a.Table1ID and Table2.Datetime = a.Datetime
inner join Table3 on Table2.ID = Table3.Table2ID
inner join Table1 on Table1.ID = Table2.Table1ID
where Name = 'me'
EDIT:
I am using LINQ to EF. I have tried
var myEntities = new MyEntities();
var a = myEntities.Table2.Select(x => new { x.Id, x.Datetime }).GroupBy(x => x.Id).Select(x => new { Id = x.Key, Datetime = x.Max(y => y.Datetime) });
var b = myEntities.Table2.Join(a.ToList(), x => new { Id = x.Table1Id, x.Datetime }, y => new { y.Id, y.Datetime }, (x, y) => x.Id);
return myEntities.Table3.Where(x => x.Name == "me" && b.Contains(x.Table2Id)).Select(x => x.Table2.Table1).ToList();
but it comes back with
System.NotSupportedException: Unable to create a constant value of type 'Anonymous type'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
highlighting the last line above. The stack trace shows it is ToList() throwing this exception.
I figured it out; it was that
var b = myEntities.Table2.Join(a.ToList(),
should be
var b = myEntities.Table2.Join(a,
Also, the query should be
var myEntities = new MyEntities();
var a = myEntities.Table2.Select(x => new { x.Table1Id, x.Datetime }).GroupBy(x => x.Table1Id).Select(x => new { Table1Id = x.Key, Datetime = x.Max(y => y.Datetime) });
var b = myEntities.Table2.Join(a, x => new { x.Table1Id, x.Datetime }, y => new { y.Table1Id, y.Datetime }, (x, y) => x);
return b.Join(myEntities.Table3, x => x.Id, y => y.Table2Id, (x, y) => new { x.Table1, y.Name }).Where(x => x.Name == "me").Select(x => x.Table1).ToList();

Resources