I have problems in designing an extended query in the ...PreprocessQuery() Method of a LightSwitch query.
1st of all, I tell you in a simplified way, what works:
partial void NeedHelp_PreprocessQuery(bool Admin, ref IQueryable<Device> query)
{
// Some code...
query = query.Where<Device>(d => d.IsAvailable());
}
The query does not show any compile error and does what it should do.
Now, when I try to put the logic into a method and use its delegate in the query, there's no compile error either, but I get an exception. Here is the code:
private bool Logic(Device TheDevice, bool Admin)
{
return Admin ? true : TheDevice.IsAvailable();
}
partial void NeedHelp_PreprocessQuery(bool Admin, ref IQueryable<Device> query)
{
// Some code...
Func<Device, bool, bool> LogicDelegate = new Func<Device, bool, bool>(this.Logic);
query = query.Where<Device>(d => LogicDelegate(d, Admin));
}
The Exception is in German, I try to translate the essential:
The expression is not supported. Expression:
Invoke(value(LightSwitchApplication.ApplicationDataService+<>c__DisplayClass4).LogicDelegate, d, value(LightSwitchApplication.ApplicationDataService+<>c__DisplayClass4).Admin)
Message of inner exception:
The type "ApplicationData.Implementation.Device" cannot be used for a parameter of type "LightSwitchApplication.Device".
Since I am only using Device, I do not understand this confusion between ApplicationData.Implementation.Device and LightSwitchApplication.Device! What am I doing wrong?
Or is this kind of call simply not possible in LightSwitch?
There is no support for inline code in linq2sql - its just imagination ;).
When you do something as 'item.Trim()' behind the scenes this will be translate to the SQL command LTRIM(RTRIM(item))
You may check Views in MSSQL.
Related
Does anyone know of any way to overcome NotSupportedException? I have a method against a User:
public virtual bool IsAbove(User otherUser)
{
return HeirarchyString.StartsWith(otherUser.HeirarchyString);
}
And I want to do:
_session.Query<User>.Where(x => loggedInUser.IsAbove(x));
But this throws a NotSupportedException. The real pain though is that using
_session.Query<User>.Where(x => loggedInUser.HeirarchyString.StartsWith(x.HeirarchyString));
works absolutely fine. I don't like this as a solution, however, because it means that if I change how the IsAbove method works, I have to remember all the places where I have duplicated the code whenever I want to update it
Name the specification expression and reuse that, e.g:
public Expression<Func<....>> IsAboveSpecification = (...) => ...;
public virtual bool IsAbove(User otherUser)
{
return IsAboveSpecification(HeirarchyString, otherUser.HeirarchyString);
}
Reuse IsAboveSpecification in the query as needed. If the IsAbove() method is used often use can cache the result of the Compile() method on the expression.
Below is the code where I try to do a simple Linq-to-entities framework query, and I want to also access the results one by one:
inctDomainContext innn = new inctDomainContext();
var exx = from c in innn.cordonnes select c;
foreach (var i in exx) {
//doing something here but the programe doesn't enter the loop
}
Why doesn't the program enter into foreach loop?
it appears you're working with WCF Ria Services in Silverlight. This is totally different from how things work when using EntityFramework directly. In your case, you have to "load" the data, before being able to access it.
To do this, you have to call the "Load" method on the domain context and pass in the query you need (in your case GetCoordonneQuery()), and then you can pass a callback to be executed when the load asynchronous call is finished. The callback will have access to the results of the query. Here's an example:
....
context.Load(GetCoordonneQuery(),OnLoadCoordonneCompleted,null)
....
void OnLoadCoordonneCompleted(LoadOperation<Coordonne> loadOp)
{
foreach(var coordonne in loadOp.Entities)
{
//do something with the data
}
}
when the OnLoadCoordonneCompleted is called (i.e: when the asynchronous load call is finished), the context.Coordonnes will be loaded and contain the data you want.
Hope this helps
Are you sure there is data in there?
Try this:
inctDomainContext innn = new inctDomainContext();
bool exxAny = innn.cordonnes.Any();
Then if exxAny is false, there is no data in the collection and hence, the foreach does nothing.
I am having a weird pattern of response time when using the Entity Framework for SQL communication.
This is from my web host:
This is from my local server:
It's the increase in response time I am worried about.
I have narrowed the problem down to one single line in code
Nop.Data > EfRepository.cs > public void Insert(T entity) > _entities.Add(entity);
Yes I know this very specific for the NopCommerce, but the point is really that I am looking her for help on how to debug this.
Are there some events I can catch that display the SQL being executed?
Or what other things can I do to find out more what is actually happening in the Entity Framework in that above command.
For debugging EF queries, the easiest thing is to cast the query to ObjectQuery and use ToTraceString:
var query = myContext.MyTable
.Where(r => r.Id == searchId)
.Select(r => r);
Console.WriteLine(((ObjectQuery)query).ToTraceString());
This will show the underlying SQL for the query, and you can run the queries manually to debug why they are slow. Here is the MSDN link:
http://msdn.microsoft.com/en-us/library/system.data.objects.objectquery.totracestring.aspx
If you're trying to get the SQL which is run when you call SaveChanges() on your context, it's not as easy. You could take a look at EFTracingProvider:
http://blogs.msdn.com/b/jkowalski/archive/2009/06/11/tracing-and-caching-in-entity-framework-available-on-msdn-code-gallery.aspx
Or, assuming you use SQL Server, you can go directly to SQL Profiler and capture the T-SQL statements (this is my preferred approach).
In EF6, you can also do this in the constructor of your dbcontext
Example
public BookServiceContext() : base("name=BookServiceContext")
{
// New code:
this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
}
This will log to the console every SQL query EF generates. See this article for more information http://blog.oneunicorn.com/2013/05/08/ef6-sql-logging-part-1-simple-logging/
Another example might be very helpful for someone.
public class MyDbContext : DbContext
{
private readonly ILoggerFactory _loggerFactory;
public MyDbContext(DbContextOptions<MyDbContext> options, ILoggerFactory loggerFactory) : base(options)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// Enable logging
optionsBuilder.UseLoggerFactory(_loggerFactory);
if (System.Diagnostics.Debugger.IsAttached)
optionsBuilder.EnableSensitiveDataLogging();
base.OnConfiguring(optionsBuilder);
}
}
I've just modified a method for handling my DDD commands (previously it had no return type):
public static CommandResult<TReturn> Execute<TCommand, TReturn>(TCommand command)
where TCommand : IDomainCommand
{
var handler = IoCFactory.GetInstance<ICommandHandler<TCommand, TReturn>>();
return handler.Handle(command);
}
The method is fine, and does what I want it to do, however using it creates some fugly code:
CommandResult<Customer> result =
DomainCommands.Execute<CustomerCreateCommand, Customer>
(
new CustomerCreateCommand(message)
);
Before I added the Customer return type TReturn, it was nice and tidy and the method could infer the types from its usage. However that's no longer possible.
Is there any way using any new C# features that I could rewrite the above to make it tidier, i.e. using Func, Action, Expression, etc? I'm probably expecting the impossible, but I'm getting fed up of writing so much code to just call a single method that used to be very simple.
One option to reduce it slightly is to have a static generic type for the type parameter that can't be inferred, allowing you to have a generic method with just one type parameter that can be inferred:
public static class DomainCommands<TReturn>
{
public static CommandResult<TReturn> Execute<TCommand>(TCommand command)
where TCommand : IDomainCommand
{
var handler = IoCFactory.GetInstance<ICommandHandler<TCommand, TReturn>>();
return handler.Handle(command);
}
}
Then:
var result = DomainCommands<Customer>.Execute(new CustomerCreateCommand(msg));
It's not much nicer, but it's slightly better. Of course, if the domain command type itself could be generic, that might help - so CustomerCreateCommand would implement IDomainCommand<Customer> for example. If you still needed a nongeneric IDomainCommand, you could make IDomainCommand<T> derive from IDomainCommand.
I have a LINQ object with an additional method added to it. The class has no disposable properties or methods, but FxCop is raising the error "Types that own disposable fields should be disposable" and referencing that class.
I've reduced the code this far and still receive the error:
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from wiki in context.Wikis
from pageTag in context.VirtualWikiPageTags
select new {};
return null;
}
}
}
However, if I remove EITHER of the from clauses, FxCop stops giving the error:
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from pageTag in context.VirtualWikiPageTags
select new {};
return null;
}
}
}
Or
partial class WikiPage
{
public PagePermissionSet GetUserPermissions(Guid? userId) {
using (WikiTomeDataContext context = new WikiTomeDataContext()) {
var permissions =
from wiki in context.Wikis
select new {};
return null;
}
}
}
PagePermissionSet is not disposable.
Is this a false positive? Or is the LINQ code somehow generating a disposable field on the class? If it isn't a false positive, FxCop is recommending that I implement the IDisposable interface, but what would I do in the Dispose method?
EDIT:
The full FxCop error is:
"Implement IDisposable on 'WikiPage' because it
creates members of the following IDisposable types:
'WikiTomeDataContext'. If 'WikiPage' has previously
shipped, adding new members that implement IDisposable
to this type is considered a breaking change to existing
consumers."
Edit 2:
This is the disassembled code that raises the error:
public PagePermissionSet GetUserPermissions(Guid? userId)
{
using (WikiTomeDataContext context = new WikiTomeDataContext())
{
ParameterExpression CS$0$0001;
ParameterExpression CS$0$0003;
var permissions = context.Wikis.SelectMany(Expression.Lambda<Func<Wiki, IEnumerable<VirtualWikiPageTag>>>(Expression.Property(Expression.Constant(context), (MethodInfo) methodof(WikiTomeDataContext.get_VirtualWikiPageTags)), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki") }), Expression.Lambda(Expression.New((ConstructorInfo) methodof(<>f__AnonymousType8..ctor), new Expression[0], new MethodInfo[0]), new ParameterExpression[] { CS$0$0001 = Expression.Parameter(typeof(Wiki), "wiki"), CS$0$0003 = Expression.Parameter(typeof(VirtualWikiPageTag), "pageTag") }));
return null;
}
}
Edit 3:
There does appear to be a closure class containing a reference to the DataContext. Here is its disassembled code:
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public WikiTomeDataContext context;
// Methods
public <>c__DisplayClass1();
}
My guess is that the two From clauses generate a call to SelectMany with a closure on your data context. The instance of the closure has a field to the datacontext which is causes the FxCop warning. This is nothing to worry about.
There's only one instance of your datacontext, which you clean up via the using block. Because the closure doesn't have a finalizer there's no performance or saftey implication here in the FxCop warning.
I noticed that this is a partial class. Have you checked the other implementation file for the class and see if it has an IDisposable member that is not being disposed?
I don't think the generated closure is at fault here. Closures are generated with certain attributes that should cause FxCop to ignore warnings like this.
EDIT
Further investigation by the OP showed this to be an issue with an IDisposable field being lifted into a closure.
Unfortunately there isn't a whole lot you can do about this. There is no way to make the closure implement IDisposable. Event if you could there is no way to call IDisposable on the closure instance.
The best way to approach this problem is to rewrite your code in such a way that a disposable value does not get captured in the closure. Disposable fields should always be disposed when they are finished and capturing it in a closure prevents you from doing this.
If you're returning a LINQ query from your method, consumers will iterate over the results using foreach.
When a consumer finishes a foreach loop, it internally calls dispose on the IEnumerable source (in this case, your LINQ query). This will dispose the WikiTomeDataContext.
However, if a consumer made a call to method returning a LINQ query but never iterated over the results, it would appear that enumerable would never be disposed (that is, until the garbage collector cleaned up the object). This would lead to your WikiTomeDataContext not being disposed until garbage collection.
One way you might be able to get around this problem is by calling .ToArray on the result of your LINQ query, call dispose on your context, then return the array.
Your code that gives the error uses WikiDataContext.
Your two examples that do not give an error use WikiTomeDataContext.
Maybe there is some difference between these two that is causing the error.