Entity Framework, SQLite and Lazy loading - c#

Hi I had developed a C# Budget application using SQL Compact and EF4, I created the EF model through the VS2010 Entity Data Model template. It is all working very well. However I am considering developing a iPhone app to support cash transactions and thought it would be better to have the back end DB supported on both platforms. After creating the SQLite DB and creating a new model I have come across a problem when trying to access referenced data via the Navigation properties in my model. I am getting a NullReferenceException when trying to display a property of a referenced table.
When using the following code I get the exception on the last line:
BudgetEntities budget = new BudgetEntities();
var accounts = budget.BankAccounts.ToList();
foreach (BankAccount a in accounts)
{
Console.WriteLine("Name:" + a.Description);
Console.WriteLine("Number:" + a.AccountNumber);
Console.WriteLine("Type:" + a.BankAccountType.AccountType); //Exception occurs here.
}
Strange thing is that the exception doesn't occur in this example. I'm not sure what is going on?
BudgetEntities budget = new BudgetEntities();
var accoutTypes = budget.BankAccountTypes;
var account = new BankAccount();
account.ID = Guid.NewGuid();
account.AccountTypeID = accoutTypes.First(t => t.AccountType.StartsWith("Credit")).ID;
account.BSB = "3434";
account.AccountNumber = "32323";
account.Description = "Test";
account.TrackingAccount = true;
budget.AddObject("BankAccounts", account);
budget.SaveChanges();
var accounts = budget.BankAccounts.ToList();
foreach (BankAccount a in accounts)
{
Console.WriteLine("Name:" + a.Description);
Console.WriteLine("Number:" + a.AccountNumber);
Console.WriteLine("Type:" + a.BankAccountType.AccountType); //Exception doesn't happen.
}
This is only a simple example and I know I could fix it by adding .Include("BankAccountTypes") to the query however I have other queries that are quite complex that are creating object which include properties from referenced object with in the query and I am not quite sure how to get around this issue for them.
EDIT:
After having a break between projects I have come back to this problem and I have finally resolved my problem. it had nothing to do with the code. It was with the data. I had converted a SQL Compact database to SQLite via a dump and load and had the syntax wrong for my Guid column data. I was inserting the Guid as '7cee3e1c-7a2b-462d-8c3d-82dd6ae62fb4' when it should have been x'7cee3e1c7a2b462d8c3d82dd6ae62fb4'
Hopefully the hair I pulled out working through this problem will grow back :)
Thanks everyone for your input.

In second example your code snippet begins with:
var accoutTypes = budget.BankAccountTypes;
This loads all bank account types to your application and you don't need lazy loading anymore (EF will automatically recognize that these entities were already loaded and fix relations with bank accounts).
First check if your account class is dynamic proxy (just check type of a in the debugger). If it is not you made some mistake in the class definition and lazy loading will not work. Next check if lazy loading is enabled on your context instance (budget.ContextOptions.LazyLoadingEnabled property).

Make sure the BankAccountType property is declared virtual in BudgetEntities.

Related

Connecting to mongodb sing C# quick tour not creating db or collection

I'm going through the mongoDB Driver Documentation Quick Tour for the first time. Specifically the 2.4 version.
I've created a fresh mongodb instance at the 192.168.1.50 address, and it appears to be running correctly.
The MongoDB documentation gives the following example:
var client = new MongoClient("mongodb://192.168.1.50:27017");
#It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("testDB");
#It’s ok if the collection doesn’t yet exist. It will be created upon first use.
var collection = database.GetCollection<BsonDocument>("testCollection");
However, when I go on my server, and I enter the mongo console
mongo
And I list the databases using
show dbs
The output is only
admin 0.000GB
local 0.000GB
Is there anything else I should have done to make this work? I'm getting no errors on try/catch, and it appears to be running fine.
Troubleshooting
So far I've confirmed that mongodb is running by using the following:
netstat -plntu
Shows mongod running on 27017 in the LISTEN state.
I'd also be interested in knowing if there's a way on the mongodb server to view live connections, so I could see if it were actually successfully connecting.
Well the problem is that you need to create almost one collection in order to persist the created database (weird right?) i tested it with robomongo and works in that way.
The problem is that GetCollection method is not creating the target collection, you can try with this code:
static void Main(string[] args)
{
var client = new MongoClient("mongodb://192.168.1.50:27017");
//# It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("test");
//# It’s ok if the collection doesn’t yet exist. It will be created upon first use.
string targetCollection = "testCollection";
bool alreadyExists = database.ListCollections().ToList().Any(x => x.GetElement("name").Value.ToString() == targetCollection);
if (!alreadyExists)
{
database.CreateCollection(targetCollection);
}
var collection = database.GetCollection<BsonDocument>(targetCollection);
}
It turns out that a method I had found on how to set multiple bindIp's was incorrect. The problem wasn't with the C# at all. I found the solution here
In case that ever goes away, here's the current settings I had to follow for multiple ip's
edit file /etc/mongod.conf
Wrap the comma-separated-Ips with brackets
bindIp = [127.0.0.1, 192.168.184.155, 96.88.169.145]
My original code worked fine, I just didn't have the brackets on the bindIp.

view SqlXmlCommand.ExecuteCommand() on SQL server

I am having an issue where I am looking at a legacy application that is using SqlXmlCommand objects to get data from the database. There is an .xsd file that has the tables that are being used, and what fields, their relationships etc. The issue that we are having is it works most of the time, but not all. I am wondering if there is a way to check what is actually being run on Sql Server. I don't have the SQL profiler installed so that option is out.
the code looks like:
SqlXmlCommand xcmd = new SqlXmlCommand(DataAccess.OleDbConnectionString);
xcmd.CommandType = SqlXmlCommandType.XPath;
xcmd.SchemaPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"myXsd.xsd"));
xcmd.XslPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, String.Format(#"myXsl.xsl", ReportType)));
xcmd.CommandText = "id[#PK=$PK]";
SqlXmlParameter p = xcmd.CreateParameter();
p.Name = "#PK";
p.Value = Id;
using (Stream s = xcmd.ExecuteStream()) { ... }
This blows up at the ExectureStream() with the error:
SQLXML: error loading XML result (XML document must have a top level element.)
We believe that there is some data abnormality that is causing the xml to not generate properly, and that is why we want to see what is exactly run.
Cheers
You can try the below two queries, you might need to tweak it a little, but to give you an idea, the first gives you a list of all requests, and the second will give you the detail of the request by its request id (session_id)
SELECT *
FROM sys.dm_exec_requests
DBCC INPUTBUFFER (12345)
Although I would personally rather try and debug the C# app first and view what's being sent over to the server from the VS debugger before bothering with checking what's being run on SQL Server
Also, DBCC INPUTBUFFER might give you something like EXECUTE dbo.MyStoredProc 'params...', to dig deeper, or otherwise a more straightforward query, you can run this
SELECT r.session_id, r.[status], r.command, t.[text]
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.[sql_handle]) t

Entity Framework not flushing data to the database

I am using Visual Studio 2012. I have a very simple Products table in a Local Database (cleverly named Database1). It has two fields: id and Name. I preloaded it with a few test data.
The following code should update the Name of the first Product. Internally, it does. I can retrieve all Products and see that the first one's Name is "Shirt." But the change is never flushed to the database. The record is never updated. Examining the database reveals that the name has not been changed.
My question is simple: Why are changes not being sent to the database?
using (var context = new Database1Entities())
{
var products = context.Products;
products.First().Name = "Shirt";
context.SaveChanges();
}
Thanks in advance.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
EDIT:
I tried my best to enter the full code and output here. But, no matter what I do, I continue to get the "Your post appears to contain code that is not properly formatted" error message. After 30 minutes I am giving up.
EDIT:
The code and output is here: http://pastebin.com/GmQtwAND
I discovered the issue...and its solution.
The "Copy to Output Directory" property of the database file was set to "Copy always." This, of course, meant that every time the application was built, a fresh copy was placed into the Bin directory. The fix was to set it to "Copy if newer." Doh.
In other words, the changes were being persisted in the database, but then the database was being clobbered when the application got rebuilt.
Well this could mean that you're not tracking changes, how about you try to set the State to -> Modified and see if it's going to work:
var product = products.First();
product.Name = "Shirt";
product.State = EntityState.Modified;
context.SaveChanges();
If you want to enable it for the context you can do it like this:
context.Configuration.AutoDetectChangesEnabled = true;

Form view update issues

I am using asp.net with a c# back end to create a job website with a master and detail view.
To pull data I am using entity framework that was reverse engineered code first from a SQL server 2005 instance running on the same xp machine that I am doing development on. I would like the detail view on the website to be able view and edit existing records selected on the master view, but also be able to insert records.
So far I gotten to the point where the detail view can be used both view and insert records but editing has been unsuccessful as of yet. I don't get an error on update, and the I see no change reflected anywhere.
Some of the solutions I've seen say that you have to have DataKeyNames defined. (In my case I have used a field: Job_UID, which is actually how I connected the detail and master views.)
I have tried to made sure that I have the update query defined properly by reducing the number of items in the where clause to just reflect my PK and also by testing the query in the query designer.
Here are my queries:
SelectCommand="SELECT Job_Details.Job_UID, Job_Details.Job_Title, Job_Details.Job_Store_ID, Job_Details.Job_Type_Id, Job_Details.Job_Description, Job_Details.Job_Responsibilities, Job_Details.Job_Pay, Job_Details.Job_Supervisor, Job_Details.Job_Start_Date, Job_Details.Job_End_Date, Job_Details.Job_Meta_Post_StartDate, Job_Details.Job_Meta_Post_EndDate, Job_Details.Job_Meta_Keywords, Store_Look_Up.Store_Name, Store_Look_Up.Store_Region, Store_Look_Up.Store_Address, Job_Type.Job_Type_Name, Job_Type.Job_Type_Description FROM Job_Details INNER JOIN Job_Type ON Job_Details.Job_Type_Id = Job_Type.Job_Type_Id INNER JOIN Store_Look_Up ON Job_Details.Job_Store_ID = Store_Look_Up.Store_Id WHERE (Job_Details.Job_UID = #Job_UID)"
InsertCommand="INSERT INTO Job_Details(Job_UID, Job_Title, Job_Store_ID, Job_Type_Id, Job_Description, Job_Responsibilities, Job_Pay, Job_Supervisor, Job_Start_Date, Job_End_Date, Job_Meta_Post_StartDate, Job_Meta_Post_EndDate, Job_Meta_Keywords) VALUES (#Job_UID, #Job_Title, #Job_Store_ID, #Job_Type_Id, #Job_Description, #Job_Responsibilities, #Job_Pay, #Job_Supervisor, #Job_Start_Date, #Job_End_Date, #Job_Meta_Post_StartDate, #Job_Meta_Post_EndDate, #Job_Meta_Keywords)"
UpdateCommand="UPDATE Job_Details SET Job_Title = #Job_Title, Job_Store_ID = #Job_Store_ID, Job_Type_Id = #Job_Type_Id, Job_Description = #Job_Description, Job_Responsibilities = #Job_Responsibilities, Job_Pay = #Job_Pay, Job_Supervisor = #Job_Supervisor, Job_Start_Date = #Job_Start_Date, Job_End_Date = #Job_End_Date, Job_Meta_Post_StartDate = #Job_Meta_Post_StartDate, Job_Meta_Post_EndDate = #Job_Meta_Post_EndDate, Job_Meta_Keywords = #Job_Meta_Keywords WHERE (Job_UID = #Original__Job_UID)">
The rest of the solutions I've seen seem to involve a lot of custom coding. Shouldn't there be a way to do this just using Visual Studio's code generator, with some coding tweaks?
Any help would be appreciated, and thanks in advance!
The problem was with my update command:
I used the ItemUpdatedEvent of my FormView to determine how many rows were modified: 0 in my case.
string textToDisplay = string.Empty;
textToDisplay += "AffectedRows: " + e.AffectedRows.ToString() + "|";
Label1.Text = textToDisplay;
Once I was clearly able to see how many rows were being updated, I proceeded to test the query. I replaced #Original_Job_UID with the PK. And it worked on the page.
Then I looked through some MSDN documentation and saw that the filter should have been
#Job_UID. I entered it and it worked!
Hope this helps you!

ActiveDirectory error 0x8000500c when traversing properties

I got the following snippet (SomeName/SomeDomain contains real values in my code)
var entry = new DirectoryEntry("LDAP://CN=SomeName,OU=All Groups,dc=SomeDomain,dc=com");
foreach (object property in entry.Properties)
{
Console.WriteLine(property);
}
It prints OK for the first 21 properties, but then fail with:
COMException {"Unknown error (0x8000500c)"}
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Entry()
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Current()
at ActiveDirectory.Tests.IntegrationTests.ObjectFactoryTests.TestMethod1() in MyTests.cs:line 22
Why? How can I prevent it?
Update
It's a custom attribute that fails.
I've tried to use entry.RefreshCache() and entry.RefreshCache(new[]{"theAttributeName"}) before enumerating the properties (which didn't help).
Update2
entry.InvokeGet("theAttributeName") works (and without RefreshCache).
Can someone explain why?
Update3
It works if I supply the FQDN to the item: LDAP://srv00014.ssab.com/CN=SomeName,xxxx
Bounty
I'm looking for an answer which addresses the following:
Why entry.Properties["customAttributeName"] fails with the mentioned exception
Why entry.InvokeGet("customAttributeName") works
The cause of the exception
How to get both working
If one wants to access a custom attribute from a machine that is not
part of the domain where the custom attribute resides (the credentials
of the logged in user don't matter) one needs to pass the fully
qualified name of the object is trying to access otherwise the schema
cache on the client machine is not properly refreshed, nevermind all
the schema.refresh() calls you make
Found here. This sounds like your problem, given the updates made to the question.
Using the Err.exe tool here
http://www.microsoft.com/download/en/details.aspx?id=985
It spits out:
for hex 0x8000500c / decimal -2147463156 :
E_ADS_CANT_CONVERT_DATATYPE adserr.h
The directory datatype cannot be converted to/from a native
DS datatype
1 matches found for "0x8000500c"
Googled "The directory datatype cannot be converted to/from a native" and found this KB:
http://support.microsoft.com/kb/907462
I have the same failure. I´m read and saw a lot of questions about the error 0x8000500c by listing attribute from a DirectoryEntry.
I could see, with the Process Monitor (Sysinternals), that my process has read a schema file. This schema file is saved under
C:\Users\xxxx\AppData\Local\Microsoft\Windows\SchCache\xyz.sch.
Remove this file and the program works fine :)
I just encountered the issue and mine was with a web application.
I had this bit of code which pulls the user out of windows authentication in IIS and pulls their info from AD.
using (var context = new PrincipalContext(ContextType.Domain))
{
var name = UserPrincipal.Current.DisplayName;
var principal = UserPrincipal.FindByIdentity(context, this.user.Identity.Name);
if (principal != null)
{
this.fullName = principal.GivenName + " " + principal.Surname;
}
else
{
this.fullName = string.Empty;
}
}
This worked fine in my tests, but when I published the website it would come up with this error on FindByIdentity call.
I fixed the issue by using correct user for the app-pool of the website. As soon as I fixed that, this started working.
I had the same problem with a custom attribute of a weird data type. I had a utility program that would extract the value, but some more structured code in a service that would not.
The utility was working directly with a SearchResult object, while the service was using a DirectoryEntry.
It distilled out to this.
SearchResult result;
result.Properties[customProp]; // might work for you
result.Properties[customProp][0]; // works for me. see below
using (DirectoryEntry entry = result.GetDirectoryEntry())
{
entry.Properties[customProp]; // fails
entry.InvokeGet(customProp); // fails as well for the weird data
}
My gut feel is that the SearchResult is a little less of an enforcer and returns back whatever it has.
When this is converted to a DirectoryEntry, this code munges the weird data type so that even InvokeGet fails.
My actual extraction code with the extra [0] looks like:
byte[] bytes = (byte[])((result.Properties[customProp][0]));
String customValue = System.Text.Encoding.UTF8.GetString(bytes);
I picked up the second line from another posting on the site.

Categories