Tool: Visual Studio 2010
Language: C#
I have just started learning Entity Framework,I'm stuck in a problem,whenver I used Code#1 it works fine but whenever I use CODE#2,I get error (posted below)
Title: InvalidOperationException was unhandled by user code
Error Message
"The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph."
//SchoolModel.Designer.cs
public EntityCollection<Course> Courses
{
get
{ //Blah blah code }
set
{
if ((value != null))
{//Below statement is pointed by Visual Studio as Exception Thrower
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<Course>("SchoolModel.CourseInstructor", "Course", value);
}
}
}
CODE# 1:
List<string> list = new List<string>();
var prs = new Person();
using (var myEntity = new SchoolEntities())
{
var result = myEntity.People;
foreach (var ppl in result)
{
list.Add(ppl.PersonID+","+ppl.FirstMidName);
}
}
CODE# 2:
List<string> list = new List<string>();
List<Person> prsList = new List<Person>();//when using this list,problem started
var prs = new Person();
using (var myEntity = new SchoolEntities())
{
var result = myEntity.People;
foreach (var ppl in result)
{
list.Add(ppl.PersonID+","+ppl.FirstMidName);
//New code which raised exceptions
prs.PersonID = ppl.PersonID;
prs.FirstMidName = ppl.FirstMidName;
prs.LastName = ppl.LastName;
prs.Courses = ppl.Courses;
prsList.Add(prs);
//New code end
}
}
Database Diagram:
Entity Diagram:
P.S:
I followed EF tutorials at http://www.asp.net/web-forms/tutorials/getting-started-with-ef/the-entity-framework-and-aspnet-getting-started-part-3, then deviated and started to play with it :)
I did find some related error questions,but my scenario is different.
You should not set an EntityCollection, as you do in prs.Courses = ppl.Courses. The collection has already been initialized (as per exception). You only modify it by Adding Course instances to it.
Can you try by moving the initialization of prs inside of the foreach loop.
Related
Documentation and examples online about compiled async queries are kinda sparse, so I might as well ask for guidance here.
Let's say I have a repository pattern method like this to query all entries in a table:
public async Task<List<ProgramSchedule>> GetAllProgramsScheduledList()
{
using (var context = new MyDataContext(_dbOptions))
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
return await context.ProgramsScheduledLists.ToListAsync();
}
}
This works fine.
Now I want to do the same, but with an async compiled query.
One way I managed to get it to compile is with this syntax:
static readonly Func<MyDataContext, Task<List<ProgramSchedule>>> GetAllProgramsScheduledListQuery;
static ProgramsScheduledListRepository()
{
GetAllProgramsScheduledListQuery = EF.CompileAsyncQuery<MyDataContext, List<ProgramSchedule>>(t => t.ProgramsScheduledLists.ToList());
}
public async Task<List<ProgramSchedule>> GetAllProgramsScheduledList()
{
using (var context = new MyDataContext(_dbOptions))
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
return await GetAllProgramsScheduledListQuery(context);
}
}
But then on runtime this exception get thrown:
System.ArgumentException: Expression of type 'System.Collections.Generic.List`1[Model.Scheduling.ProgramSchedule]' cannot be used for return type 'System.Threading.Tasks.Task`1[System.Collections.Generic.List`1[Model.Scheduling.ProgramSchedule]]'
The weird part is that if I use any other operator (for example SingleOrDefault), it works fine. It only have problem returning List.
Why?
EF.CompileAsync for set of records, returns IAsyncEnumrable<T>. To get List from such query you have to enumerate IAsyncEnumrable and fill List,
private static Func<MyDataContext, IAsyncEnumerable<ProgramSchedule>> compiledQuery =
EF.CompileAsyncQuery((MyDataContext ctx) =>
ctx.ProgramsScheduledLists);
public static async Task<List<ProgramSchedule>> GetAllProgramsScheduledList(CancellationToken ct = default)
{
using (var context = new MyDataContext(_dbOptions))
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var result = new List<ProgramSchedule>();
await foreach (var s in compiledQuery(context).WithCancellation(ct))
{
result.Add(s);
}
return result;
}
}
i'm working on a project that is based on web scraping with .NET Framework and Html-Agility-Pack tool.
At first, i made a method that parse the Category list from https://www.gearbest.com and it's totally working fine.
But now i need to parse the products from each category list item.
For example there is appliances category https://www.gearbest.com/appliances-c_12245/, but when i run the method it returns an error :
'The underlying connection was closed: An unexpected error occurred on a receive'
Here is my code :
public void Get_All_Categories()
{
var html = #"https://www.gearbest.com/";
HtmlWeb web = new HtmlWeb();
var htmlDoc = web.Load(html);
var nodes = htmlDoc.DocumentNode.SelectNodes("/html/body/div[1]/div/ul[2]/li[1]/ul/li//a/span/../#href");
foreach (HtmlNode n in nodes)
{
Category c = new Category();
c.Name = n.InnerText;
c.CategoryLink = n.GetAttributeValue("href", string.Empty);
categories.Add(c);
}
}
This is working pretty much fine.
public void Get_Product()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var html = #"https://www.gearbest.com/appliances-c_12245/";
HtmlWeb web = new HtmlWeb();
var htmlDoc = web.Load(html);
var x = htmlDoc.DocumentNode.SelectSingleNode("//*[#id=\"siteWrap\"]/div[1]/div[1]/div/div[3]/ul/li[1]/div/p[1]/a");
Console.WriteLine(x.InnerText);
Console.WriteLine("done");
}
But this method doesn't work and it returns that error.
How can i fix this please ?
P.S : I already saw some solutions about HTTPS handling but it didn't work for me, maybe because i don't understand it.
I would appreciate any help, thank you in advance.
I have found some plugin code on the web that enables me to get the entity ID and the object type code for an entity in a plugin. The plugin is fired on RetrieveMultiple on activitypointer. The code lets me get the id and object code of the entity that is currently being viewed (which is displaying the activities grid which is firing the plugin).
This code works fine when using the web interface. However I need it to also work in the Outlook preview pane and currently it does not. The activities grid in the Outlook preview pane just says "an error has occurred". Below is the code that the plugin is using to get the details from the web header.
internal static Dictionary<string, string> GetHeaderFields(HttpContext webcontext, string objectTypeCode, string objectId)
{
Dictionary<string, string> fields = new Dictionary<string, string>();
string callerentitytype = null;
string callerentityidstring = null;
try
{
// Activities Navigation Pane
if (new List<string>(webcontext.Request.Params.AllKeys).Contains("oType"))
{
callerentitytype = webcontext.Request.Params["oType"];
callerentityidstring = webcontext.Request.Params["oId"];
}
// Activities Sub Grid
else
{
string requeststring = webcontext.Request.UrlReferrer.Query;
requeststring = requeststring.Substring(1);
string[] parts = requeststring.Split(new string[] { "=", "&" }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < parts.Length - 1; i++)
if (parts[i].ToLower() == "otype" || parts[i].ToLower() == "etc")
callerentitytype = parts[i + 1];
else if (parts[i].ToLower() == "oid" || parts[i].ToLower() == "id")
callerentityidstring = parts[i + 1];
}
fields.Add(objectTypeCode, callerentitytype);
fields.Add(objectId, callerentityidstring);
}
catch (Exception ex)
{
throw new Plugin.LoggableException(string.Format("Failed to obtain header information; {0}", ex.Message), ex.InnerException);
}
return fields;
}
The reason is that webcontext.Request.UrlReferrer is NULL. Is there anywhere else I can get this info of the 'calling' entity? (Not the activity sub grid that is triggering the plugin, but the actual parent entity that the sub grid is on).
Thanks for any help or direction with this.
This might work. Each of the activitypointers that are returned should all be "regarding" the same record (if in a sub grid). If you take say the 1st one and examine the regardingobjectid property, that should be an entity reference which will give you the logical name of the parent and it's guid. If that works, it will work across all clients (in theory anyway).
Trying to update a list of Incident records. The first one in the foreach updates, the next one throws an exception stating "the context is not currently tracking the incident entity". Is this the correct way to code this?
var openCases = (from o in xrmContext.IncidentSet
where o.StateCode == 0
select o).Take(5).ToList();
foreach (var c in openCases)
{
var numDays = ((TimeSpan) (DateTime.Now - c.CreatedOn)).Days;
Console.WriteLine("case age: {0}, case number:{1}", numDays, c.TicketNumber);
c.new_caseage = numDays;
xrmContext.UpdateObject(c);
xrmContext.SaveChanges();
}
When you call SaveChanges() it, in addition to saving any modified entity records, detaches all entity records being tracked in the context. Therefore, the second time you call SaveChanges() the entity record is not being tracked and you receive the error.
You should move the xrmContext.SaveChanges(); line to be after the foreach loop.
var openCases = (from o in xrmContext.IncidentSet
where o.StateCode == 0
select o).Take(5).ToList();
foreach (var c in openCases)
{
var numDays = ((TimeSpan) (DateTime.Now - c.CreatedOn)).Days;
Console.WriteLine("case age: {0}, case number:{1}", numDays, c.TicketNumber);
c.new_caseage = numDays;
xrmContext.UpdateObject(c);
}
xrmContext.SaveChanges();
All entities are detached by the OrganizationServiceContext after calling the SaveChanges method. To continue using the data context against previously retrieved entities, the entities need to be reattached.
However, the preference is to apply all modifications under a single call to SaveChanges, and then dispose the context, to avoid the need to reattach.
http://msdn.microsoft.com/en-us/library/gg695783.aspx
http://msdn.microsoft.com/en-us/library/gg334504.aspx#track_related
A better way to do what your try to do is using the message ExecuteMultipleRequest, with it can configure how many record to process for every iteration (internal iteration)
var openCases = (from o in xrmContext.IncidentSet
where o.StateCode == 0
select o).Take(5).ToList();
var requestWithResults = new ExecuteMultipleRequest()
{
// Assign settings that define execution behavior: continue on error, return responses.
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
// Create an empty organization request collection.
Requests = new OrganizationRequestCollection()
};
foreach (var c in openCases)
{
var numDays = ((TimeSpan) (DateTime.Now - c.CreatedOn)).Days;
c.new_caseage = numDays;
CreateRequest createRequest = new CreateRequest { Target = c };
requestWithResults.Requests.Add(createRequest);
}
ExecuteMultipleResponse responseWithResults =
(ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
Hope it helps
Note: I'm specifically not using Fluent NHibernate but am using 3.x's built-in mapping style. However, I am getting a blank recordset when I think I should be getting records returned.
I'm sure I'm doing something wrong and it's driving me up a wall. :)
Background / Setup
I have an Oracle 11g database for a product by IBM called Maximo
This product has a table called workorder which lists workorders; that table has a field called "wonum" which represents a unique work order number.
I have a "reporting" user which can access the table via the maximo schema
e.g. "select * from maximo.workorder"
I am using Oracle's Managed ODP.NET DLL to accomplish data tasks, and using it for the first time.
Things I've Tried
I created a basic console application to test this
I added the OracleManagedClientDriver.cs from the NHibernate.Driver on the master branch (it is not officially in the release I'm using).
I created a POCO called WorkorderBriefBrief, which only has a WorkorderNumber field.
I created a class map, WorkorderBriefBriefMap, which maps only that value as a read-only value.
I created a console application with console output to attempt to write the lines of work orders.
The session and transaction appear to open correct,
I tested a standard ODP.NET OracleConnection to my connection string
The Code
POCO: WorkorderBriefBrief.cs
namespace PEApps.Model.WorkorderQuery
{
public class WorkorderBriefBrief
{
public virtual string WorkorderNumber { get; set; }
}
}
Mapping: WorkorderBriefBriefMap.cs
using NHibernate.Mapping.ByCode;
using NHibernate.Mapping.ByCode.Conformist;
using PEApps.Model.WorkorderQuery;
namespace ConsoleTests
{
public class WorkorderBriefBriefMap : ClassMapping<WorkorderBriefBrief>
{
public WorkorderBriefBriefMap()
{
Schema("MAXIMO");
Table("WORKORDER");
Property(x=>x.WorkorderNumber, m =>
{
m.Access(Accessor.ReadOnly);
m.Column("WONUM");
});
}
}
}
Putting it Together: Program.cs
namespace ConsoleTests
{
class Program
{
static void Main(string[] args)
{
NHibernateProfiler.Initialize();
try
{
var cfg = new Configuration();
cfg
.DataBaseIntegration(db =>
{
db.ConnectionString = "[Redacted]";
db.Dialect<Oracle10gDialect>();
db.Driver<OracleManagedDataClientDriver>();
db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
db.BatchSize = 500;
db.LogSqlInConsole = true;
})
.AddAssembly(typeof(WorkorderBriefBriefMap).Assembly)
.SessionFactory().GenerateStatistics();
var factory = cfg.BuildSessionFactory();
List<WorkorderBriefBrief> query;
using (var session = factory.OpenSession())
{
Console.WriteLine("session opened");
Console.ReadLine();
using (var transaction = session.BeginTransaction())
{
Console.WriteLine("transaction opened");
Console.ReadLine();
query =
(from workorderbriefbrief in session.Query<WorkorderBriefBrief>() select workorderbriefbrief)
.ToList();
transaction.Commit();
Console.WriteLine("Transaction Committed");
}
}
Console.WriteLine("result length is {0}", query.Count);
Console.WriteLine("about to write WOs");
foreach (WorkorderBriefBrief wo in query)
{
Console.WriteLine("{0}", wo.WorkorderNumber);
}
Console.WriteLine("DONE!");
Console.ReadLine();
// Test a standard connection below
string constr = "[Redacted]";
OracleConnection con = new OracleConnection(constr);
con.Open();
Console.WriteLine("Connected to Oracle Database {0}, {1}", con.ServerVersion, con.DatabaseName.ToString());
con.Dispose();
Console.WriteLine("Press RETURN to exit.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine("Error : {0}", ex);
Console.ReadLine();
}
}
}
}
Thanks in advance for any help you can give!
Update
The following code (standard ADO.NET with OracleDataReader) works fine, returning the 16 workorder numbers that it should. To me, this points to my use of NHibernate more than the Oracle Managed ODP.NET. So I'm hoping it's just something stupid that I did above in the mapping or configuration.
// Test a standard connection below
string constr = "[Redacted]";
OracleConnection con = new Oracle.ManagedDataAccess.Client.OracleConnection(constr);
con.Open();
Console.WriteLine("Connected to Oracle Database {0}, {1}", con.ServerVersion, con.DatabaseName);
var cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandText = "select wonum from maximo.workorder where upper(reportedby) = 'MAXADMIN'";
cmd.CommandType = CommandType.Text;
Oracle.ManagedDataAccess.Client.OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader.GetString(0));
}
con.Dispose();
When configuring NHibernate, you need to tell it about your mappings.
I found the answer -- thanks to Oskar's initial suggestion, I realized it wasn't just that I hadn't added the assembly, I also needed to create a new mapper.
to do this, I added the following code to the configuration before building my session factory:
var mapper = new ModelMapper();
//define mappingType(s) -- could be an array; in my case it was just 1
var mappingType = typeof (WorkorderBriefBriefMap);
//use AddMappings instead if you're mapping an array
mapper.AddMapping(mappingType);
//add the compiled results of the mapper to the configuration
cfg.AddMapping(mapper.CompileMappingForAllExplicitlyAddedEntities());
var factory = cfg.BuildSessionFactory();