Entity Framework Except Fields - entity-framework

I want to call all columns but except some fields. For example only base table select not include relationships.
var _person= db.Persons.Select(x => new
{
x.id,
x.Name,
x.Surname,
x.Age,
....
x.Address.City ..
}).ToList();
I want to select => var _person= db.Persons.UNSelect(x => x.Address).ToList();
Unselect or Except or nondisplay ???

Related

Using string_agg in the many-to-many relation

I have entities like Product(Id, Name) and Keyword(Id, Description), and there is a many-to-many relationship between them.
The essence of my task is the following, I need to do a full-text search on Name and Description columns, using EF CORE 6
I already have some SQL code that works fine.
SELECT a."Id", a."Name" as name, k.txt
FROM "Products" AS a
LEFT JOIN (
SELECT x."ProductsId" as Id, string_agg(y."Description", ' ') as txt
FROM "ProductKeywords" x
JOIN "Keywords" y ON y."Id" = x."KeywordId"
GROUP BY 1
) k ON a."Id" = k.Id
WHERE to_tsvector(concat_ws(' ', a."Name", k.txt))
## to_tsquery('Some text');
And I need to write some LINQ code that will do something similar, but I have a problem with string_agg, and I don't understand how to implement it in LINQ and EF CORE will reflect it correctly
I tried to do the following
var products = _context.Products
.Select(e => new
{
Id = e.Id,
Name = e.Name,
Keywords = string.Join(" ", e.Keywords.Select(q => q.Description))
}).Where(e => EF.Functions.ToTsVector(e.Keywords).Matches("Some text")).ToList();
But I get an error, and it's most likely because of string.Join
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
Got the result, using linq2db
var query = _context.Products.ToLinqToDB()
.LeftJoin(_context.ProductsKeywords.ToLinqToDB().GroupBy(r => r.ProductId).Select(e => new {
Key = e.Key,
Txt = e.StringAggregate(",", t => t.Keyword.Description).ToValue()
}),
(product, productKeyword) => product.Id == productKeyword.Key,
(i, j) => new {
Id = i.Id,
Txt = j.Txt
}).Select(e => new {
Id = e.Id,
Txt = EF.Functions.ToTsVector(e.Txt)
}).Where(w => w.Txt.Matches("Some text"));

Select with fields to include in detail table with EF Core

How can I select whitch fields should be included for detail table in EF Core.
I tried with this query:
var result= this.context.MainTable
.Include(t => t.DetailTable)
.Select(t => new {
id = t.Id,
values = t.DetailTable.Select(t2 => t2.SomeField)
})
.ToArray();
I would expect this result to single query, but it does not. It automatically execute query one by one for every row in MainTable and select SomeField.

Entity Framework LINQ Query match all members of child collection

I have a Site table that has a many-to-many relationship with a UtilityServiceConnection table using a linking table called LinkSiteUtilityServiceConnection. Given a set of ServiceConnectionIds, I need to locate the Site that is exclusively linked to all of them and no more. I think I should be able to write the query using All on the collection but it's not working as expected.
var serviceConnectionIds = new[] { 546892, 546911, 546923 };
var sites1 = db.Sites
.Where(x => x.LinkSiteUtilityServiceConnections.All(y => serviceConnectionIds.Contains(y.UtilityServiceConnectionId)))
.ToList();
Assert.AreEqual(1, sites1.Count); //fails
This produces the query below that returns ~250,000 records when I expect to get one.
SELECT [Extent1].*
FROM [dbo].[Site] AS [Extent1]
WHERE NOT EXISTS (SELECT 1 AS [C1]
FROM [dbo].[LinkSiteUtilityServiceConnection] AS [Extent2]
WHERE ([Extent1].[SiteId] = [Extent2].[SiteId])
AND ((NOT ([Extent2].[UtilityServiceConnectionId] IN (546892, 546911, 546923)))
OR (CASE
WHEN ([Extent2].[UtilityServiceConnectionId] IN (546892, 546911, 546923)) THEN cast(1 as bit)
WHEN (NOT ([Extent2].[UtilityServiceConnectionId] IN (546892, 546911, 546923))) THEN cast(0 as bit)
END IS NULL)))
Why isn't All working as I expect? What's the best way to write this query?
check this code:
query 1:
var sites1 = db.Sites
.Where(x => serviceConnectionIds.All(y =>
x.LinkSiteUtilityServiceConnections
.Select(u => u.UtilityServiceConnectionId).Contains(y)))
.ToList();
query 2:
var query = db.Posts.AsQueryable();
var sites1 = serviceConnectionIds.Aggregate(query,
(current, item) => current.Where(e => e.LinkSiteUtilityServiceConnections
.Any(c => c.UtilityServiceConnectionId== item))).ToList();

Entity framework finding foreign keys

I want to find all the foreign keys of an entity in my entity model.
I have used the following to get a list of all the properties for an entity:
var workspace = _entities.MetadataWorkspace;
var entityType = workspace.GetItems<EntityType>(DataSpace.CSpace).FirstOrDefault(e => e.Name == tablename);
var keyNames = entityType.Members.Select(k => k.Name);
Is there any way to find only those properties which have foreign key associations? And also that property in the reference entity with which it is associated?
I worked out the solution:
var fk = _entities.MetadataWorkspace
.GetItems<AssociationType>(DataSpace.CSpace)
.Where(a => a.IsForeignKey);
// Check if the table has any foreign constraints for that column
var fkname = fk
.Where(x => x.ReferentialConstraints[0].ToRole.Name == tablename)
.Where(x => x.ReferentialConstraints[0].ToProperties[0].Name == columnname);
// Get the corresponding reference entity column name
var refcol = fkname
.Select(x => x.ReferentialConstraints[0].FromProperties[0].Name)
.First();

Linq join query

For example
DB with 2 Tables
Book [BookId (int), Title (nvarchar), ShowInWebshop (bit)] and
InventoryDetail [InventoryDetailId (int), BookId (int), Quantity (int)]
Execute: SELECT * FROM Books LEFT JOIN InventoryDetails ON books.BookId = InventoryDetails.BookId
The output shows all Book columns and related InventoryDetails columns (including the InventoryDetails.BookId column)
..so far so good ...
Trying to transform this query into a Linq one (using LinqPad, comparing several examples, common sense, etc.) I compilated the following generic List (because I wanted a present a list)
private List<Book> Books(int count){
var books = webshopDB.Books
.Join<Book, InventoryDetail, int, Book>( webshopDB.InventoryDetails,
b => b.BookId,
i => i.BookId,
(b, i) => b )
.Where(b => b.ShowInWebshop == true)
.Take(count)
.ToList();
return books
}
This module returns a list of books! Not the one I expected, though! It returns only book details such as Title and ShowOnSite NOT the details from the InventoryDetail table: Quantity
What do I forget?
The result how it works so far ...
public ActionResult Index()
{
// This return a list of tuples {(WebshopDB.Models.Book, WebshopDB.Models.InventoryDetail)}
// Each tuple containing two items:
// > Item1 {WebshopDB.Models.Book}
// > Item2 {WebshopDB.Models.InventoryDetail}
var tuple_books = ListOfTuples_BookInventoryDetail(5);
...
// next step(s)
// add a ViewModel viewmodel
// ...
return (viewmodel);
}
private List<Tuple<Book, InventoryDetail>> ListOfTuples_BookInventoryDetail(int count)
{
var list_of_tuples = new List<Tuple<Book, InventoryDetail>>();
var showbooks = webshopDB.Books
.Join(webshopDB.InventoryDetails, b => b.BookId, i => i.BookId, (b, i) => new { b = b, i = i })
.Where(o => (o.b.ShowInWebshop == true))
.Where(o => o.b.BookThumbUrl.Contains(".jpg"))
.OrderByDescending(o => o.b.OrderDetails.Count())
.Take(count);
foreach (var item in showbooks)
{
list_of_tuples.Add( Tuple.Create<Book, InventoryDetail>( (item.b), (item.i) ) );
}
return list_of_tuples;
}
You need to select from both tables, e.g.
from b in webshop.Books
from i in webshopDB.InventoryDetails
where i.BookId = b.BookId
select b.BookId, b.Title, b.ShowInWebshop, i.InventoryDetailId, i.Quantity
You're getting books because you specified that in your Join statement with the final selector of => b. You want to select both, so use this:
var query = webshopDB.Books.Join(webshopDB.InventoryDetails,
b => b.BookId, i => i.BookId,
(b, i) => new { Book = b, InventoryDetail = i });
Then when you iterate over the results you can use:
foreach (var item in query)
{
Console.WriteLine(item.Book.SomeProperty);
Console.WriteLine(item.InventoryDetail.SomeProperty);
}
The other problem with your method is that the return type is a List<Book>. So the above won't work since a Book class is separate from an InventoryDetail class. You need to setup a new class to encompass both, or use a Tuple<Book, InventoryDetail> if using .NET 4.0.
To return a particular property you could modify the statement to:
var query = webshopDB.Books.Join(webshopDB.InventoryDetails,
b => b.BookId, i => i.BookId,
(b, i) => new { b.BookId, i.Quantity });
Again, you need an appropriate return type if you're returning a List<T>.
EDIT: to get a Dictionary<Book, InventoryDetail> you could use the earlier query as follows:
var query = webshopDB.Books.Join(webshopDB.InventoryDetails,
b => b.BookId, i => i.BookId,
(b, i) => new { Book = b, InventoryDetail = i })
.ToDictionary(o => o.Book, o => o.InventoryDetail);
Of course you can use the Where and Take as necessary before the ToDictionary call. You can also project just the properties you need as the query just before this one. You need to project it into an anonymous type via the new keyword (it was missing earlier so take another look at it).
Quering the answer of SoftwareRockstar in LinqPad4 generates errors! So, that's not the way!
//This does works (in LinqPad4)
from b in webshopDB.Books
from i in webshopDB.InventoryDetails
where b.BookId == i.BookId
where b.ShowInWebshop == true
select new { b.Title, i.Quantity, b.ShowInWebshop }