Before I summit the front entry data (with JSF/PrimeFaces), I had to check if existing name record. view scope bean like this :
public void updateProfileListener(ActionEvent actionEvent) {
if(supplierService.isExistSupplierName(supplier.getName(), true)) return;
// else saveDate();
}
and database check code like this :
userDatabase.createQuery("select c from Supplier c where c.name = :name")
.setParameter("name", name)
.getResultList();
It is just regular query sql for checking if existing name, but it is still to update the new data from front entry, May I know what happened?
BalusC's rigth!
Now, if you want find olny 1 supplier you may try add other data validation in where clause( well, i dont know your business logic :D ).
But, you really want resultList I think better use 'like'
select c from Supplier c where c.name like ...
Related
i have problem with translated query, ToList(), AsEnumerable etc.
I need construct or create query which is shared.
Branches -> Customer -> some collection -> some collection
Customer -> some collection -> some collection.
Do you help me how is the best thingh how to do it and share the query.
i access to repository via graphql use projection etc.
public IQueryable<CustomerTableGraphQL> BranchTableReportTest(DateTime actualTime, long userId)
{
var r =
(
from b in _dbContext.Branches
let t = Customers(b.Id).ToList()
select new CustomerTableGraphQL
{
Id = b.Id,
Name = b.Name,
Children =
(
from c in t
select new CustomerTableGraphQL
{
Id = c.Id,
Name = c.Name
}
)
.AsEnumerable()
}
);
return r;
}
public IQueryable<Customer> Customers(long branchId) =>
_dbContext.Customers.Where(x => x.BranchId.Value == branchId).ToList().AsQueryable();
Some example how to doit and share iquearable between query
Using ToList / AsEnumerable etc. entirely defeats the potential benefits of using IQueryable. If your code needs to do this rather than return an IQueryable<TEntity> then you should be returning IEnumerable<TResult> where TResult is whatever entity or DTO/ViewModel you want to return.
An example of an IQueryable<TEntity> repository pattern would be something like this:
public IQueryable<Customer> GetCustomersByBranch(long branchId) =>
_dbContext.Customers.Where(x => x.BranchId.Value == branchId);
Normally I wouldn't really even have a repository method for that, I'd just use:
public IQueryable<Customer> GetCustomers() =>
_dbContext.Customers.AsQueryable();
... as the "per branch" is simple enough for the consumer to request without adding methods for every possible filter criteria. The AsQueryable in this case is only needed because I want to ensure the result matches the IQueryable type casting. When your expression has a Where clause then this is automatically interpreted as being an IQueryable result.
So a caller calling the Repository's "GetCustomers()" method would look like:
// get customer details for our branch.
var customers = _Repository.GetCustomers()
.Where(x => x.BranchId == branchId)
.OrderBy(x => x.LastName)
.ThenBy(x => x.FirstName)
.Select(x => new CustomerSummaryViewModel
{
CustomerId = x.Id,
FirstName = x.FirstName,
LastName = x.LastName,
// ...
}).Skip(pageNumber * pageSize)
.Take(pageSize)
.ToList();
In this example the repository exposes a base query to fetch data, but without executing/materializing anything. The consumer of that call is then free to:
Filter the data by branch,
Sort the data,
Project the data down to a desired view model
Paginate the results
... before the query is actually run. This pulls just that page of data needed to populate the VM after filters and sorts as part of the query. That Repository method can serve many different calls without needing parameters, code, or dedicated methods to do all of that.
Repositories returning IQueryable that just expose DbSets aren't really that useful. The only purpose they might provide is making unit testing a bit easier as Mocking the repository is simpler than mocking a DbContext & DbSets. Where the Repository pattern does start to help is in enforcing standardized rules/filters on data. Examples like soft delete flags or multi-tenant systems where rows might belong to different clients so a user should only ever search/pull across one tenant's data. This also extends to details like authorization checks before data is returned. Some of this can be managed by things like global query filters but wherever there are common rules to enforce about what data is able to be retrieved, the Repository can serve as a boundary to ensure those rules are applied consistently. For example with a soft-delete check:
public IQueryable<Customer> GetCustomers(bool includeInactive = false)
{
var query = _context.Customers.AsQueryable();
if (!includeInactive)
query = query.Where(x => x.IsActive);
return query;
}
A repository can be given a dependency for locating the current logged in user and retrieving their roles, tenant information, etc. then use that to ensure that:
a user is logged in.
The only data retrieved is available to that user.
An appropriate exception is raised if specific data is requested that this user should never be able to access.
An IQueryable repository does require a Unit of Work scope pattern to work efficiently within an application. IQueryable queries do no execute until something like a ToList or Single, Any, Count, etc. are called. This means that the caller of the repository ultimately needs to be managing the scope of the DbContext that the repository is using, and this sometimes rubs developers the wrong way because they feel the Repository should be a layer of abstraction between the callers (Services, Controllers, etc.) and the data access "layer". (EF) To have that abstraction means adding a lot of complexity that ultimately has to conform to the rules of EF (or even more complexity to avoid that) or significantly hamper performance. In cases where there is a clear need or benefit to tightly standardizing a common API-like approach for a Repository that all systems will conform to, then an IQueryable pattern is not recommended over a general IEnumerable typed result. The benefit of IQueryable is flexibility and performance. Consumers decide and optimize for how the data coming from the Repository is consumed. This flexibility extends to cover both synchronous and asynchronous use cases.
EF Core will translate only inlined query code. This query will work:
public IQueryable<CustomerTableGraphQL> BranchTableReportTest(DateTime actualTime, long userId)
{
var r =
(
from b in _dbContext.Branches
select new CustomerTableGraphQL
{
Id = b.Id,
Name = b.Name,
Children =
(
from c in _dbContext.Customers
where c.BranchId == b.Id
select new CustomerTableGraphQL
{
Id = c.Id,
Name = c.Name
}
)
.AsEnumerable()
}
);
return r;
}
If you plan to reuse query parts, you have to deal with LINQKit and its ExpandableAttribute (will show sample on request)
How can I include a related entity, but only select the top 1?
public EntityFramework.Member Get(string userName)
{
var query = from member in context.Members
.Include(member => member.Renewals)
where member.UserName == userName
select member;
return query.SingleOrDefault();
}
According to MSDN:
"Note that it is not currently possible to filter which related entities are loaded. Include will always bring in all related entities."
http://msdn.microsoft.com/en-us/data/jj574232
There is also a uservoice item for this functionality:
http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1015345-allow-filtering-for-include-extension-method
The approach to use an anonymous object works, even though it's not clean as you wish it would be:
public Member GetMember(string username)
{
var result = (from m in db.Members
where m.Username == username
select new
{
Member = m,
FirstRenewal = m.Renewals.FirstOrDefault()
}).AsEnumerable().Select(r => r.Member).FirstOrDefault();
return result;
}
The FirstRenewal property is used just to make EF6 load the first renewal into the Member object. As a result the Member returned from the GetMember() method contains only the first renewal.
This code generates a single Query to the DB, so maybe it's good enough for You.
I do it like this. It works but looks so ugly. And I don't have any clue to make it more meaningful.
I'm using .NET Framework 3.5 and MVC2
TRY TO Explain a little more...
With the following code, I set value to 'temp' again and again. if table 'temp' have 100 fields, then I have to set value 100 times. That's what I mean ugly.
//
// POST: /TableA/Create
[HttpPost]
public ActionResult Create(TableA formdata)
{
TableA temp = new TableA();
//A foreign key model in another TableB
var tbb = myDB.TableB.First(a => a.Id == formdata.TableB.Id);
temp.TableB = tbb;
//fields in this table
temp.field1= formdata.field1;
temp.field2= formdata.field2;
temp.field3= formdata.field3;
myDB.AddToTableA(temp);
myDB.SaveChanges();
return RedirectToAction("Index");
}
Separating code in layers usually helps, because you don't mix UI with business layer or data access layer... if that's what you asked, because it's rather hard to know what you's like to change in your code.
Otherwise your code looks as a mix of everything, becomes hard to maintain and understand what it does.
Edit
Instead of setting every property manually, you can do either:
Use object initializers (C# 3.0 feature)
TableA record = new TableA {
TableB = myDB.TableB.First(a => a.Id == formdata.TableB.Id),
Field1 = ... ,
...
};
Use static factory methods provided by entity classes:
TableA record = TableA.CreateTableA(/* provide all values as method parameters */);
I'm having problems querying the entity model to get additional information.
My db has a Program table with a one to many relation with an Events table. The Entity model generates the relationships just fine, but I'm unable to figure out how to query the model to get the progam object with its events.
I can do this:
var foo = from program in entities.ProgramSet
where program.StartDate > DateTime.now
orderby program.StartDate
select program;
No problems there. From what I've found on Microsofts Page (Shaping queries with Entity framework): msdn.microsoft.com/en-us/library/bb896272.aspx, if I wanted to get the child objects, I just do the following:
// Define a LINQ query with a path that returns
// orders and items for a contact.
var contacts = (from contact in context.Contact
.Include("SalesOrderHeader.SalesOrderDetail")
select contact).FirstOrDefault();
However, there is no .Include or Include that I can find on the query.
Any suggestion? I know that I can do a foreach across the results, then run a .Events.Load() on it, but doesn't that force the IQueriable result to execute the sql, instead of optomize it to run only when a .ToList() etc is called on it?
Here is some sample code from my project:
public class ProgramRepository : CT.Models.IProgramRepository
{
CTEntities db = new CTEntities();
public IQueryable<Program> FindAllPrograms()
{
return db.ProgramSet;
}
public IQueryable<Program> FindUpcomingPrograms()
{
var programs = from program in FindAllPrograms()
where program.StartDate > DateTime.Now
orderby program.StartDate
select program;
return programs;
}
With the FindUpComingPrograms I would like to have it also include the Events Data. There is a relationship between the Program and Events model. Program has a List<Events> property, that I would like to fill and return with the IQueryable method.
Thanks again!
The Include Function is part of the ObjectQuery object...
I think you are going to need to re-write your query to look something like this:
var contacts = context.Contact.Include("SalesOrderHeader.SalesOrderDetail").FirstOrDefault();
//Not sure on your dot path you might have to debug that a bit
Here is an Article that has some examples...
I must admin this is kind of funny even though I think I understand why :) I created a UnitTest to add a blog entry to try Alex suggestion about my inheritance problems. Now I come across another one.
[TestMethod]
public void UserCanAddBlogEntry()
{
var context = new EntityContext(Options.LazyLoading);
var user = (from u in context.Users
.Include("Blog.BlogEntries")
where u.Id == 1
select u).FirstOrDefault();
BlogEntry entry = new BlogEntry();
entry.Header = "Test Entry";
entry.Text = "Test Text blah blah blah";
entry.CreatedAt = DateTime.Now;
entry.Blog = user.Blog;
user.Blog.BlogEntries.Add(entry);
context.SaveChanges();
Assert.IsTrue(user.Blog.BlogEntries.Count > 0);
}
Causes the exception:
Failed UserCanAddBlogEntry Zirzle.UnitTests
Test method UserCanAddBlogEntry threw
exception:
System.InvalidOperationException:
Invalid relationship fixup detected in
the navigation property 'User' of the
entity of the type 'Profile'.
Not sure what is wrong with this picture. If I add .Include("Profile") in the get query then save changes doesnt complain any more. I tried adding a 0.1 relation end for profile but that didn't work out either. Any suggestions? I suppose stack overflows personal EF expert might have an explanation :)
Well this one is interesting.
I'm assuming that Blog.BlogEntries is the inverse of BlogEntry.Blog
I'm also assuming that all the properties on all classes are virtual, so the EF can proxy the classes.
Given these assumptions some objects will be proxied (user and user.Blog) because the ObjectContext constructed them and some won't be proxied (entry) because you created them yourself.
Proxied classes automatically do fix-up, i.e. keep both ends of a relationship in sync
So doing this on a proxied user.Blog:
user.Blog.BlogEntries.Add(entry)
will automatically set entry.Blog to user.Blog at the same time to keep both relationships in sync for you.
On the other hand because entry isn't proxied this:
entry.Blog = user.Blog
won't do fixup.
So in this code you are essentially doing one half of the fix-up twice. We should probably gracefully handle this situation, but obviously we aren't, I will talk this through with the team.
Having said all that I suggest you do something a little simplier:
// notice there is no need to get the User just the users blog
var blog = (from u in context.Users
where u.Id == 1
select u.Blog).Single();
and just do this:
BlogEntry entry = new BlogEntry();
entry.Header = "Test Entry";
entry.Text = "Test Text blah blah blah";
entry.CreatedAt = DateTime.Now;
entry.Blog = blog;
//because BlogEntry inherits from Post if I remember your model
context.Posts.Add(entry);
context.SaveChanges();
This should work.
Alex