How to use the Exact array value instead of Contains [duplicate] - c#

This question already has answers here:
LINQ equal instead of Contains
(3 answers)
Closed 5 years ago.
I need to use Equals method or something similar instead of using Contains method because i want to search in database for the exact values in selectedDeviceTypeIDs array not any of it.
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs
.Split(',')
.Select( Guid.Parse )
.AsEnumerable();
query = query
.Where( j =>
j.HospitalDepartments.Any( jj =>
jj.Units.Any( m =>
m.Devices.Any( w =>
selectedDeviceTypeIDs.Contains( w.DeviceTypeID )
)
)
)
);
Here is my full code
public HttpResponseMessage GetAvailableHospitalsByAjax(System.Guid? DirectorateOfHealthID = null, System.Guid? UnitTypeID = null, string DeviceTypeIDs = null)
{
Context db = new Context();
var query = db.Hospitals.AsQueryable();
if (DeviceTypeIDs != null)
{
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs.Split(',').Select(Guid.Parse).AsEnumerable();
query = query.Where(j => j.HospitalDepartments.Any(jj => jj.Units.Any(m => m.Devices.Any(w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID)))));
}
if (UnitTypeID != null)
{
query = query.Where(j => j.HospitalDepartments.Any(www => www.Units.Any(u => u.UnitTypeID == UnitTypeID)));
}
if (DirectorateOfHealthID != null)
{
query = query.Where(h => h.DirectorateHealthID == DirectorateOfHealthID);
}
query = query.Where(j => j.HospitalDepartments.Any(u => u.Units.Any(d => d.Devices.Any(s => s.Status == Enums.DeviceStatus.Free)))
&& j.HospitalDepartments.Any(hd => hd.Units.Any(u => u.Beds.Any(b => b.Status == Enums.BedStatus.Free))));
var list = query.ToList();
return Request.CreateResponse(HttpStatusCode.OK, list);
}

Your problem is not Contains() but with the Any() method used in your query which will return true immediately after it finds a device whose DeviceTypeID is in the provided selectedDeviceTypeIDs list.
If you need to check if all the devices of a unit match all the items in the list, you could use:
query = query
.Where(j =>
j.HospitalDepartments.Any(jj =>
jj.Units.Any(m =>
m.Devices.All(
w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID))
&&
selectedDeviceTypeIDs.All(
g => m.Devices.Select(d => d.DeviceTypeID).Contains(g))
)
)
);
Note that if you have duplicate items in the selectedDeviceTypeIDs but not in the Devices of the Unit, it will still return true.

Related

how can Get Sum of selected Fields by Id Linq C#?

var totalDistributed = db.Distributions
.Select(m => m.Product.ProductName == (string)productNameComboBox.SelectedItem).Any()
? db.Distributions.Sum(m => m.Piece) : 0;
var totalStock = db.StockIns
.Select(m => m.Product.ProductName == (string)productNameComboBox.SelectedItem)
.Any() ? db.StockIns.Sum(m => m.Piece) : 0;
Using this code, I get the sum of all values, but I want to get sum of specific values through productId using a linq query. productId comes from productNameComboBox.
You can try Where filter function instead of Select if Where filter function does not find any matches, Sum will return 0.
var totalDistributed = db.Distributions
.Where(m => m.Product.ProductName == (string)productNameComboBox.SelectedItem).Sum(m => m.Piece);
var totalStock = db.StockIns
.Where(m => m.Product.ProductName == (string)productNameComboBox.SelectedItem).Sum(m => m.Piece);

Reflected property(dynamic property) inside Linq lambda

How can i replace x.Demographic.AgeRange with any other field?
Eg
var field_to_check = "Country";
x.Demographic.ReflectedProperty(field_to_check)=="USA"
var field_to_check = "AgeRnage";
x.Demographic.ReflectedProperty(field_to_check)=="20-30"
I Tried with a refelcted property. but cant succeed.
Favourability = db.Questions
.OrderByDescending(x => x.Responces.Count(y => y.Responseval == Constants.options.Agree || y.Responseval == Constants.options.Tend_to_Agree))
.Select(z => new
{
z.QuestionTitle,
Count = z.Responces.Where(x =>
x.Demographic.AgeRange == repval &&
(x.Responseval == Constants.options.Agree || x.Responseval == Constants.options.Tend_to_Agree)
)
.Count()
})
.Select(z => new
{
z.QuestionTitle,
z.Count,
Perc = ((z.Count / totresponcecount) * 100)
}
)
.ToList();
so that i can write only one linq statement as dynamic filtering rather than switch statements for all required properties.
You can construct the expression tree from multiple different ones. Use LinqKit, and write:
Expression<Func<Demography, string>> fieldSpec = d => d.AgeRange;
And then in your expession:
var exp = db.Questions.AsExpadable() ... fieldSpec.Expand(x.Demographic) == repval ...
Now all you need to do is construct the fieldSpec dynamically, which is an excercise for you :)

Comparing list with list inside another list with linq [duplicate]

I am getting this error for the query below
Unable to create a constant value of type API.Models.PersonProtocol. Only primitive types or enumeration types are supported in this context
ppCombined below is an IEnumerable object of PersonProtocolType, which is constructed by concat of 2 PersonProtocol lists.
Why is this failing? Can't we use LINQ JOIN clause inside of SELECT of a JOIN?
var persons = db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y) =>
new PersonDTO
{
personId = y.personId,
addressId = y.addressId,
favoriteId = x.favoriteId,
personProtocol = (ICollection<PersonProtocol>) ppCombined
.Where(a => a.personId == x.personId)
.Select( b => new PersonProtocol()
{
personProtocolId = b.personProtocolId,
activateDt = b.activateDt,
personId = b.personId
})
});
This cannot work because ppCombined is a collection of objects in memory and you cannot join a set of data in the database with another set of data that is in memory. You can try instead to extract the filtered items personProtocol of the ppCombined collection in memory after you have retrieved the other properties from the database:
var persons = db.Favorites
.Where(f => f.userId == userId)
.Join(db.Person, f => f.personId, p => p.personId, (f, p) =>
new // anonymous object
{
personId = p.personId,
addressId = p.addressId,
favoriteId = f.favoriteId,
})
.AsEnumerable() // database query ends here, the rest is a query in memory
.Select(x =>
new PersonDTO
{
personId = x.personId,
addressId = x.addressId,
favoriteId = x.favoriteId,
personProtocol = ppCombined
.Where(p => p.personId == x.personId)
.Select(p => new PersonProtocol
{
personProtocolId = p.personProtocolId,
activateDt = p.activateDt,
personId = p.personId
})
.ToList()
});
In my case, I was able to resolve the issue by doing the following:
I changed my code from this:
var r2 = db.Instances.Where(x => x.Player1 == inputViewModel.InstanceList.FirstOrDefault().Player2 && x.Player2 == inputViewModel.InstanceList.FirstOrDefault().Player1).ToList();
To this:
var p1 = inputViewModel.InstanceList.FirstOrDefault().Player1;
var p2 = inputViewModel.InstanceList.FirstOrDefault().Player2;
var r1 = db.Instances.Where(x => x.Player1 == p1 && x.Player2 == p2).ToList();
Don't know if anyone searches for this.
I had the same problem. A select on the query and then doing the where (or join) and using the select variable solved the problem for me.
(problem was in the collection "Reintegraties" for me)
query.Select(zv => new
{
zv,
rId = zv.this.Reintegraties.FirstOrDefault().Id
})
.Where(x => !db.Taken.Any(t => t.HoortBijEntiteitId == x.rId
&& t.HoortBijEntiteitType == EntiteitType.Reintegratie
&& t.Type == TaakType))
.Select(x => x.zv);
hope this helps anyone.
I had this issue and what I did and solved the problem was that I used AsEnumerable() just before my Join clause.
here is my query:
List<AccountViewModel> selectedAccounts;
using (ctx = SmallContext.GetInstance()) {
var data = ctx.Transactions.
Include(x => x.Source).
Include(x => x.Relation).
AsEnumerable().
Join(selectedAccounts, x => x.Source.Id, y => y.Id, (x, y) => x).
GroupBy(x => new { Id = x.Relation.Id, Name = x.Relation.Name }).
ToList();
}
I was wondering why this issue happens, and now I think It is because after you make a query via LINQ, the result will be in memory and not loaded into objects, I don't know what that state is but they are in in some transitional state I think. Then when you use AsEnumerable() or ToList(), etc, you are placing them into physical memory objects and the issue is resolving.
It's worth adding, since the OP's code sample doesn't provide enough context to prove otherwise, but I received this error as well on the following code:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId.Equals(refersToRetailSaleId));
}
Apparently, I cannot use Int32.Equals in this context to compare an Int32 with a primitive int; I had to (safely) change to this:
public RetailSale GetByRefersToRetailSaleId(Int32 refersToRetailSaleId)
{
return GetQueryable()
.FirstOrDefault(x => x.RefersToRetailSaleId == refersToRetailSaleId);
}
Just add AsEnumerable() andToList() , so it looks like this
db.Favorites
.Where(x => x.userId == userId)
.Join(db.Person, x => x.personId, y => y.personId, (x, y).ToList().AsEnumerable()
ToList().AsEnumerable()

LINQ: How Can I Use Equals in query

I need to use Equals method or something similar instead of using Contains method because i want to search in database for the exact values in selectedDeviceTypeIDs array not any of it.
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs
.Split(',')
.Select( Guid.Parse )
.AsEnumerable();
query = query
.Where( j =>
j.HospitalDepartments.Any( jj =>
jj.Units.Any( m =>
m.Devices.Any( w =>
selectedDeviceTypeIDs.Contains( w.DeviceTypeID )
)
)
)
);
Here is my full code:
public HttpResponseMessage GetAvailableHospitalsByAjax(System.Guid? DirectorateOfHealthID = null, System.Guid? UnitTypeID = null, string DeviceTypeIDs = null)
{
Context db = new Context();
var query = db.Hospitals.AsQueryable();
if (DeviceTypeIDs != null)
{
IEnumerable<Guid> selectedDeviceTypeIDs = DeviceTypeIDs.Split(',').Select(Guid.Parse).AsEnumerable();
query = query.Where(j => j.HospitalDepartments.Any(jj => jj.Units.Any(m => m.Devices.Any(w => selectedDeviceTypeIDs.Contains(w.DeviceTypeID)))));
}
if (UnitTypeID != null)
{
query = query.Where(j => j.HospitalDepartments.Any(www => www.Units.Any(u => u.UnitTypeID == UnitTypeID)));
}
if (DirectorateOfHealthID != null)
{
query = query.Where(h => h.DirectorateHealthID == DirectorateOfHealthID);
}
query = query.Where(j => j.HospitalDepartments.Any(u => u.Units.Any(d => d.Devices.Any(s => s.Status == Enums.DeviceStatus.Free)))
&& j.HospitalDepartments.Any(hd => hd.Units.Any(u => u.Beds.Any(b => b.Status == Enums.BedStatus.Free))));
var list = query.ToList();
return Request.CreateResponse(HttpStatusCode.OK, list);
}
EF6 supports the SQL IN operator if the foo in foo.Contains( ) is an IList<T>, for example, this Linq:
Int32[] desired = new Int32[] { 1, 2, 3, 4 };
IQueryable<Item> itemsQuery = db.Items.Where( item => desired.Contains( item.SomeValue ) );
...will be converted into this:
SELECT Item.* FROM Items WHERE SomeValue IN ( 1, 2, 3, 4 )
I'm not entirely certain on the specifics, but I think if you convert your selectedDeviceTypeIDs from IQueryable<Guid> to Guid[] (or at least IList<Guid>) then EF will also generate an IN query for you.

Linq Query with a Where clause in an Include statement [duplicate]

This question already has answers here:
EF: Include with where clause [duplicate]
(5 answers)
Closed 2 years ago.
I am trying to replace my big, ugly query; although ugly it works as desired:-
using (var ctx = new Data.Model.xxxTrackingEntities())
{
var result = ctx.Offenders
.Join(ctx.Fees, o => o.OffenderId, f => f.OffenderId,
(o, f) => new { Offenders = o, Fees = f })
.Join(ctx.ViolationOffenders, o => o.Fees.ViolationId, vo => vo.ViolationId,
(o, vo) => new { Offenders = o, ViolationOffenders = vo })
.Join(ctx.Violations, v => v.ViolationOffenders.ViolationId, vo => vo.ViolationId,
(v, vo) => new { Violations = v, ViolationOffenders = vo })
.Where(o => o.Violations.Offenders.Offenders.YouthNumber != "")
.ToList();
gvwData.DataSource = result;
}
with the following linq Query:-
var result = ctx.Offenders
.Include(o => o.Fees.Where(f => f.Amount != null))
.Include(o => o.ViolationOffenders)
.Include(o => o.ViolationOffenders.Select(of => of.Violation))
.Where(o => o.YouthNumber != "" && o.FirstName != "")
.ToList();
I am blowing up on the 2nd line of the query... once I add the Where clause... o => o.Fees.Where(f=> f.Amount != null)
The error message I get...
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
In addition, I tried writing my query as:-
var result = ctx.Offenders
.Include(o => o.Fees)
.Include(o => o.ViolationOffenders)
.Include(o => o.ViolationOffenders.Select(of => of.Violation))
.Where(o => o.YouthNumber != "" && o.FirstName != "" && o.Fees.Where(f=> f.Amount != null))
.ToList();
But then I get the following error:-
Operator '&&' cannot be applied to operands of type 'bool' and 'System.Collections.Generic.IEnumerable
I know the concept is right, but I need help with the syntax.
You cant have a Where inside the Where, but you can use Any which will return a boolean
var result = ctx.Offenders
.Include(o => o.Fees)
.Include(o => o.ViolationOffenders)
.Include(o => o.ViolationOffenders.Select(of => of.Violation))
.Where(o => o.YouthNumber != "" && o.FirstName != ""
&& o.Fees.Any(f=> f.Amount != null)) // here
.ToList();
In .Net 5 Filtered include feature is added (EF Core 5.0).
Supported operations are: Where, OrderBy, OrderByDescending, ThenBy, ThenByDescending, Skip, and Take
using (var context = new BloggingContext())
{
var filteredBlogs = context.Blogs
.Include(blog => blog.Posts
.Where(post => post.BlogId == 1)
.OrderByDescending(post => post.Title)
.Take(5))
.ToList();
}
MSDN Reference : https://learn.microsoft.com/en-us/ef/core/querying/related-data/eager

Categories

Resources