this is my first post here and I'm also new to C# / OO and LinqPAD. (translate to: I may mis-use concepts or terms due to being in 'learning mode')
I have an application that I've narrowed my bug down to the following query. I decided to try out LinqPAD to solve the issue in a constrained environment.
We are using Entity Framework for our database interactions. I am using LinqPAD's "C# Program" selection.
I found a great tutorial on how to use entities in LinqPAD and this seems to be working. (Proof: 'aEntities' does not return an error like it did when the entities were not connected properly)
So let's get to the issue.
At the 'var' I get: "NullReferenceException: Object reference not set to an instance of an object."
The reason I'm here asking this is every single example I see out there uses this 'var' approach. It does not work for some reason. I've tried declaring 'qryDC', creating a new instance of it and then assigning it. (I'm feeling weak knowledge wise here, but am reading and learning.)
I have read John Saunders epic write up about this topic. (Wow man! Thanks!)
What is a NullReferenceException, and how do I fix it?
I however was not able to translate that knowledge to address my issue (learning curve).
Here is the code:
void Main(AEntities aEntities)
{
decimal fmProjectUID = 1123;
var qryDC =
from pnp in aEntities.PNonPRs
from p in aEntities.Projects
from pt in aEntities.PurchaseTypes
from wbs in aEntities.P32
from pc in aEntities.PPhases
where pnp.ProjectUID == p.ProjectUID
where p.ProjectUID == fmProjectUID
where pnp.PurchaseTypeUID == pt.PurchaseTypeUID
where pnp.P32UID == wbs.P32UID
where pt.IsNonPR == 1
orderby pt.PurchaseTypeID
select new
{
PNonPrUID = pnp.PNonPrUID
,PurchaseTypeID = pt.PurchaseTypeID
,PhaseCode = pnp.ProjectPhase.PhaseCode
,DANbr = pnp.AType.DANbr
,PreAmt = pnp.PreAmt
,POStDate = pnp.POStDate
,POFDate = pnp.POFDate
,BaseAmt = pnp.BaseAmt
,Notes = pnp.Notes
,ChangedByName = pnp.ChangedByName
};
}
Let me know if you need more info.
And thank you for your time, effort and thoughts.
You can't just arbitrarily assign arguments to the Main method and expect them to be filled in. Your aEntities variable is null when you run this, thus the null reference exception. You need to instantiate your context.
void Main()
{
decimal fmProjectUID = 1123;
var aEntities = new AEntities();
var qryDC = from pnp in aEntities.PNonPRs
from p in aEntities.Projects
from pt in aEntities.PurchaseTypes
// etc...
}
Alternatively, if you defined your connection in LINQPad and then selected said connection for the query you can omit the creation of the AEntities and just use the following.
void Main()
{
decimal fmProjectUID = 1123;
var qryDC = from pnp in PNonPRs
from p in Projects
from pt in PurchaseTypes
// etc...
}
I would also suggest you familiarize yourself with the debugger in Visual Studio and LINQPad. Had you set a breakpoint and examined the variables you would have seen that aEntities was null.
Related
I have been dealing with a really frustrating EF Core (newest version) error. I'm not sure at this point if I am doing something wrong or if it's a bug. Any help the community can provide would be appreciated.
The error is in regards to Entity Framework Core and translating a LINQ expression to SQL. The below code translates to SQL properly. The query variable below could potentially have a variety of Where expressions and Includes applied to it with no issue.
// This works fine
query.Select(price => new Customer {
Name = price.Payer.Name,
Code = price.Payer.Code,
City = price.Payer.City,
ParentCode = price.Payer.ParentCode,
ParentLevel = CustomerLevel.Corporate,
CustomerLevel = CustomerLevel.Payer
}).Distinct().ToListAsync();
As soon as I add a call to OrderBy, it will not evaluate. If I remove the call to Distinct, it once again works, but I can't have both. I've tried several different ways to build the expression and several workarounds that I've found around the interwebz, and nothing seems to resolve it.
// This throws error
// query is of type IQueryable<Price>
query.Select(price => new Customer {
Name = price.Payer.Name,
Code = price.Payer.Code,
City = price.Payer.City,
ParentCode = price.Payer.ParentCode,
ParentLevel = CustomerLevel.Corporate,
CustomerLevel = CustomerLevel.Payer
}).Distinct().OrderBy(cust => cust.Name).ToListAsync();
Also, placement of the OrderBy does not seem to matter. Based on what I've read, the call to Distinct removes all prior ordering, so this one is not too surprising.
// This also throws error
// query is of type IQueryable<Price>
query
.OrderBy(price => price.payer.Name)
.Select(price => new Customer {
Name = price.Payer.Name,
Code = price.Payer.Code,
City = price.Payer.City,
ParentCode = price.Payer.ParentCode,
ParentLevel = CustomerLevel.Corporate,
CustomerLevel = CustomerLevel.Payer
}).Distinct().ToListAsync();
I actually found the cause of the issue today. The ParentCode property (used at line ParentCode = price.Payer.ParentCode) is actually a property on the base class that is not mapped to the table, so EF apparently did not know what to do with it. The very strange part of this is that it worked without the OrderBy. Changing that line to ParentCode = price.Payer.CorporateCode resolved the issue.
Thanks for anyone that took a look at this.
I've tried to reduce this example to remove the OrganizationServiceProxy/XrmServiceContext, but now I believe the issue is originating there. I'm pulling data from a Dynamics 365 instance using the code generated by CrmSvcUtil.exe from Microsoft. Here is the relevant snippet:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
CrmServiceClient client = new CrmServiceClient(userName, CrmServiceClient.MakeSecureString(password), string.Empty, orgName, isOffice365: true);
using (OrganizationServiceProxy service = client.OrganizationServiceProxy)
{
XrmServiceContext crm = new XrmServiceContext(service);
var q = crm.CreateQuery<Account>();
List<Account> accounts = q.Where(x => x.AccountNumber != x.dynamics_integrationkey).ToList();
}
I get the following exception:
variable 'x' of type '{company-specific}.Account' referenced from scope '', but it is not defined
This is happening on the last line when the Linq is actually executed. It's only when it's created through the Microsoft.Xrm.Sdk.Client.OrganizationServiceContext that I get the error.
Things I've checked:
I get the error when comparing any two fields on the same object (not just Account), even when both are the same exact data type.
If I replace crm.CreateQuery... with a hand-populated List...AsQueryable() the Linq works fine
Most frustratingly, if I work through an intermediary list with List<Account> a = q.ToList(); to rasterize the result set first then this all works fine. It takes much longer to run because I've forfeited any lazy loading, but it works without error.
I've looked at other answers related to the referenced from scope '' but not defined Linq error, but they are all about malformed Linq. I know this Linq is well formed because it works fine if I change the underlying Queryable.
Clearly something is different between a List...ToQueryable() and the Microsoft.Xrm.Sdk.Linq.Query<> created by the XrmServiceContext (which inherits CreateQuery from Microsoft.Xrm.Sdk.Client.OrganizationServiceContext), but I don't know what it is.
The query you are trying to build (compare a field value with another field value on the same entity) is not possible in Dynamics.
The LINQ Provider still uses QueryExpression under the hood, meaning that your LINQ condition will be converted in a ConditionExpression, and that comparison is not possible.
Similar questions:
https://social.microsoft.com/Forums/en-US/d1026ed7-56fd-4f54-b382-bac2fc5e46a7/linq-and-queryexpression-compare-entity-fields-in-query?forum=crmdevelopment
Dynamics QueryExpression - Find entity records where fieldA equals fieldB
This morning I realized that my answer contained the flaw of comparing two fields against each other in a LINQ query. My bad. Thank you Guido for calling that out as impossible.
I generate my proxy classes with a 3rd party tool, so I'm not familiar with the XrmServiceContext class. But, I have confirmed that XrmServiceContext inherits from Microsoft.Xrm.Client.CrmOrganizationServiceContext, which inherits from Microsoft.Xrm.Sdk.Client.OrganizationServiceContext
I use OrganizationServiceContext for LINQ queries.
If you retrieve all the accounts first by calling ToList() on the query, you can then do the comparison of the two fields. If you have too many Accounts to load all at once, you can page through them and store the mismatched ones as you go.
And, I would probably retrieve a subset of the fields rather than the whole record (as shown).
var client = new CrmServiceClient(userName, CrmServiceClient.MakeSecureString(password), string.Empty, orgName, isOffice365: true);
using (var ctx = new OrganizationServiceContext(client))
{
var q = from a in ctx.CreateQuery<Account>()
where a.AccountNumber != null
&& a.dynamics_integrationkey != null
select new Account
{
Id = a.AccountId,
AccountId = a.AccountId,
Name = a.Name,
AccountNumber = a.AccountNumber,
dynamics_integrationkey = a.dynamics_integrationkey
};
var accounts = q.ToList();
var mismatched = accounts.Where(a => a.AccountNumber != a.dynamics_integrationkey).ToList()
}
I am using entity frame work when I tried to modify rm.StatusId = 3;
I get the title question error.
Also please give me links to know each and everything about entity frame work with asp .net controlls.
if (chk.Checked == true)
{
MAtt_RequestMaster rm =
ctx.MAtt_RequestMaster.SingleOrDefault(p => p.AutoID ==id);
rm.StatusId = 3;
ctx.SaveChanges();
}
im not too familliar with lambda expressions, but i think you can do this:
MAtt_RequestMaster rm =
ctx.MAtt_RequestMaster.SingleOrDefault(p => p.AutoID ==id);
rm.YourStatusTable = (from x in ctx.YourStatusTable
where x.statusID == 3
select x).FirstOrDefault();
ctx.SaveChanges();
This problem happens because you are referencing the same object more than once. This is not a limitation of EF, but rather a safety feature to ensure you are not inserting the same object with two different IDs. So to achieve what you are trying to do, is simply create a new object and add the newly created object to the database.
** This issue often happens inside loops. If you are using a while or foreach loop, make sure to have the New Created Object INSIDE the loop body.
try this:
MAtt_RequestMaster rm = new Matt_RequestMaster();
rm.StatusId = 3;
ctx.MAtt_RequestMasters.Attach(rm);
ctx.SaveChanges();
I want to change all my queries from QueryExpression to Linq. In development time, all seems to be just fine, but I always get a cast exception at runtime (can't cast Microsoft.xrm.sdk.entity to Xrm.SystemUser -> Xrm is the early bound classes generated with CrmSvcUtil).
var context = new OrganizationServiceContext(crmService);
SystemUser x = (from c in context.CreateQuery<SystemUser>()
where c.DomainName == #"pfgc\" + Environment.UserName
select c).FirstOrDefault();
This code is straightforward. I've even tried without the Where clause and it won't change anything.
I tried the following (no FirstOrDefault and var instead of SystemUser)
var x = (from c in context.CreateQuery<SystemUser>()
where c.DomainName == #"pfgc\" + Environment.UserName
select c);
This won't throw an exception but x type is Microsoft.xrm.sdk.linq.Query. What am I doing wrong? It seems to be exactly what the SDK suggests to do.
EDIT:
GCATNM has the right answer. In case someone faces the same issue, here's a sample of the working code:
public SystemUser GetCurrentUser()
{
var context = GetOrgContext();
return (from c in context.CreateQuery<SystemUser>()
where c.DomainName == #"pfgc\" + Environment.UserName
select c).FirstOrDefault();
}
public OrganizationServiceContext GetOrgContext()
{
var serviceProxy1 = new OrganizationServiceProxy(organizationUri, homeRealmUri, credentials, null);
serviceProxy1.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
return new OrganizationServiceContext(serviceProxy1);
}
I had a similar problem with LINQ-to-CRM and went back to QueryExpressions because they worked, until I found the solution in some SDK sample while looking for something else: You need to add a ProxyTypesBehavior to your IOrganizationService object. I don't know what it does, but that definitely was the change that allowed me to use LINQ with the early bound classes (as I perceive it, LINQ-to-CRM can only be used with the early bound classes).
So the line you need after creating your IOrganizationService is:
organizationService.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
I hope that helps.
It returns an Entity object, so you'll need to call ToEntity() if you want a System User object. The following should work for you:
var context = new OrganizationServiceContext(crmService);
SystemUser x = (from c in context.CreateQuery<SystemUser>()
where (string)c["DomainName"] == #"pfgc\" + Environment.UserName
select c).FirstOrDefault().ToEntity<SystemUser>();
What I have now is the following code:
Tutorial tutorial =
(from tutorial in xmlDoc.Descendants("Tutorial")
select new Tutorial
{
Author = tutorial.Element("Author").Value,
Title = tutorial.Element("Title").Value,
Date = DateTime.Parse(tutorial.Element("Date").Value),
}).First();
myTutorial.Author = tutorial.Author;
myTutorial.Title = tutorial.Title;
myTutorial.Date = tutorial.Date;
myTutorial is passed from another method. And the code below has to 'fill' it.
The question is: Is there a way to create a LINQ query, which will assign values to the properties of an existing object, rather that creating a new one.
I would like my code to look something like this:
Tutorial tutorial =
(from tutorial in xmlDoc.Descendants("Tutorial")
select myTutorial
{
Author = tutorial.Element("Author").Value,
Title = tutorial.Element("Title").Value,
Date = DateTime.Parse(tutorial.Element("Date").Value),
});
The problem I have is:
I have an object which initially only has half of it's properties set, later I need to fill the rest of the properties. This needs to be done asynchronously.
My Approach:
I use WebClient's asynchronous method DownloadStringAsync to download XML file. In the event handler I wan't to fill an object with the properties it misses. And that's why I would like to directly pass values to my object rather than creating a new one.
Please let me know if it is not the best approach.
OK, this is pure evil:
var dropThis =
(from tutorial in xmlDoc.Descendants("Tutorial")
select new
{
Author = (myTutorial.Author = (string)tutorial.Element("Author")),
Title = (myTutorial.Title = (string)tutorial.Element("Title")),
Date = (myTutorial.Date = (DateTime)tutorial.Element("Date")),
}).First();
LINQ functional queries are actually designed in such way, that they shouldn't modify existing objects or collections, i.e. preserve state (although there are ways (hacks?) to do so).
But you can pretty easily implement reflection-based method to achieve what you want.
I noticed this question and felt the need to add another dirty solution. How about Extension methods?
public static void AddTo(this IEnumerable<Tutorial> source, Tutorial projection)
{
if (source.Count() == 0)
return;
projection.Title = source.First().Title;
projection.Author = source.First().Author;
projection.Date = source.First().Date;
}
Now you can just call it to add to your current tutorial. Also, I recommend using (string) instead of .Value so you avoid null reference exceptions.
tutorialXml
.Descendants("Tutorial")
.Select(tutorial => new Tutorial
{
Author = (string) tutorial.Element("Author"),
Title = (string) tutorial.Element("Title"),
Date = DateTime.Parse((string) tutorial.Element("Date")),
})
.AddTo(myTutorial);
Anyway, Good luck. Just wanted to add a dirty solution to this ball of mud.