Breeze - Saving Entity and Associations - serialization

I am having a problem when attempting to save an entity and its associations in one request.
I am trying to do the following:
var myModel = manager.createEntity('MyModel', {
type: 1,
attributes: [
{ name: 'one', value: '1', active: true },
{ name: 'two', value: '2', active: true }
]
});
manager.addEntity(myModel);
manager.saveChanges().then(function(response) {}).fail(function(e){
console.log(e.message)
});
On the .NET MVC controller I have something like this:
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
var rtn = _contextProvider.SaveChanges(saveBundle);
return rtn;
}
Everything works completely fine until it is time to serialize the rtn variable and return it to the client. I get the following error:
exceptionMessage: "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
exceptionType: "System.InvalidOperationException"
innerException: {message: "An error has occurred.",…}
exceptionMessage: "Self referencing loop detected for property 'myModel' with type 'MyApp.Models.MyModel'. Path 'entities[0].attributes[0]'."
exceptionType: "Newtonsoft.Json.JsonSerializationException"
message: "An error has occurred."
stackTrace: " at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
↵ at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
↵ at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
↵ at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
↵ at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
↵ at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding)
↵ at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content)
↵ at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
↵--- End of stack trace from previous location where exception was thrown ---
↵ at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
↵ at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
↵ at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
↵ at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"
message: "An error has occurred."
stackTrace: null
This is because the child attributes have a reference to their parent and since the parent contains them then the parent ends up having a circular reference.
I thought Breeze would handle this but maybe it does not.
Am I doing something wrong?

Disregard! I was missing the [BreezeController] decoration.

Related

What is the best way to call named httpclients in loop without crashing the app?

Working on building Dashboard which uses 3rd party API endpoint to get data and trying to make this app real-time by using SignalR.
The way I'm trying to achieve this is, I have creacted Named Clients:
services.AddHttpClient("SBEnv", client =>
{
client.BaseAddress = new Uri(Configuration["SBEnvironment:SB_API_URL"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", (String)_cache.Get("sb"));
});
Which adds token to every request made to this client. I'm calling this client from the controller like this -
public async Task<IActionResult> getApps()
{
var request = new HttpRequestMessage(HttpMethod.Get, "apps");
var response = await _client_SB.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject(json);
return Ok(result);
}
and call hub from client and display result.
Signalr:
As I'm working on API I need to call endpoint every second or even less to make app realtime as much as possible. The basic idea "push only when something changes" behind signalr will not work in this case because of the endpoint. So I have created the hub
public class SBHub: Hub
{
}
and to call the named httpclient I created the IHostedService which calls the API every second.
internal class SignalRTimedHostedService : IHostedService, IDisposable
{
private readonly IHubContext<NonProductionHub> _hub;
private Timer _timer;
public readonly SBController _SBcontroller;
public SignalRTimedHostedService(IHubContext<SBHub> hub, SBController SBcontroller)
{
_hub = hub;
_SBcontroller = SBcontroller;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(1));
return Task.CompletedTask;
}
private void DoWork(object state)
{
var result = _SBcontroller.getApps();
_hub.Clients.All.SendAsync("TestBrodcasting", result);
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
The problem is whenever IHostedService runs it returns the first request but for subsequent requests, it is returning following info and hub gets disconnected displayed in firefox console.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 9632.0481ms 101
info: System.Net.Http.HttpClient.SBEnv.LogicalHandler[100]
Start processing HTTP request GET https://api.domain.io/apps
info: System.Net.Http.HttpClient.SBEnv.ClientHandler[100]
Sending HTTP request GET https://api.domain.io/apps
info: System.Net.Http.HttpClient.SBEnv.ClientHandler[101]
Received HTTP response after 40.6678ms - Unauthorized
and showing
fail: Microsoft.AspNetCore.SignalR.HubConnectionContext[6]
Failed writing message. Aborting connection.
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'task' with type 'System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[Microsoft.AspNetCore.Mvc.IActionResult,TestApp.Controllers.SBController+<getApps>d__2]'. Path 'arguments[0].stateMachine.<>t__builder'.
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteArguments(Object[] arguments, JsonTextWriter writer)
at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteInvocationMessage(InvocationMessage message, JsonTextWriter writer)
at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteMessageCore(HubMessage message, IBufferWriter`1 stream)
at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.WriteMessage(HubMessage message, IBufferWriter`1 output)
at Microsoft.AspNetCore.SignalR.Protocol.HubProtocolExtensions.GetMessageBytes(IHubProtocol hubProtocol, HubMessage message)
at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.GetMessageBytes(HubMessage message)
at Microsoft.AspNetCore.SignalR.SerializedHubMessage.GetSerializedMessage(IHubProtocol protocol)
at Microsoft.AspNetCore.SignalR.HubConnectionContext.WriteCore(SerializedHubMessage message)
To which I have tried to ignore it by adding -
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
But it's still showing me the same error, I'm not sure what I'm doing wrong.
How do I make this working? what I'm missing?
I'm very new to .net please don't FLIP on me.

Using Expand on List property: The argument must be of type 'IEnumerable'. OData

I use Asp.Net Web Api with OData(5.5.0-alpha2).
And I have a model:
public class Model
{
public List<Event> Events { get; set; }
public List<User> Subscribers { get; set; }
public User Owner { get; set; }
....
}
Action in controller:
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All, MaxAnyAllExpressionDepth = 10, MaxExpansionDepth = 10)]
public override IQueryable<EventsChannel> Get()
{
return Repository.Models.AsQueryable();
}
Repository.Models gives me all models with included properties.
When I try getting data with expand of Owner:
http://site.com/odata/Models()?$expand=Owner
Everything fine. But if I try to get Events:
http://site.com/odata/Models()?$expand=Events
It throws me exception:
The argument must be of type 'IEnumerable'.
 Parameter name: graph
I can’t change List to IEnumerable, and why it tells me this when List is IEnumerable?
<?xml version="1.0" encoding="utf-8"?>
<m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<m:code />
<m:message xml:lang="en-US">An error has occurred.</m:message>
<m:innererror>
<m:message>The 'ObjectContent`1' type failed to serialize the response body for content type 'application/atom+xml; charset=utf-8'.</m:message>
<m:type>System.InvalidOperationException</m:type>
<m:stacktrace></m:stacktrace>
<m:internalexception>
<m:message>The argument must be of type 'IEnumerable'.
Parameter name: graph</m:message>
<m:type>System.ArgumentException</m:type>
<m:stacktrace> at System.Web.Http.OData.Formatter.Serialization.ODataCollectionSerializer.CreateODataValue(Object graph, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEdmTypeSerializer.CreateProperty(Object graph, String elementName, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.CreateStructuralProperty(IEdmStructuralProperty structuralProperty, EntityInstanceContext entityInstanceContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.CreateStructuralPropertyBag(IEnumerable`1 structuralProperties, EntityInstanceContext entityInstanceContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteObjectInline(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObjectInline(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperty(KeyValuePair`2 navigationPropertyToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteExpandedNavigationProperties(IDictionary`2 navigationPropertiesToExpand, EntityInstanceContext entityInstanceContext, ODataWriter writer)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteEntry(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataEntityTypeSerializer.WriteObjectInline(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObjectInline(Object graph, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.<>c__DisplayClassa.<WriteToStreamAsync>b__9()
at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__10.MoveNext()</m:stacktrace>
</m:internalexception>
</m:innererror>
</m:error>

Autheracation error: Key cannot be null. Parameter name: key

I keep getting the error Key cannot be null. Parameter name: key. It looks like it looses the authCookie, but the Request.IsAuthenticated still is set to true. It's driving my crazy. Also i'm allready handling if the user is not logged in. But the error still appears.
An place where it fails is fore example here
#if (User.IsInRole("Admin"))
{
<button class="button-green white">Save</button>
}
But if look at what the user has of properties it still says IsAuthenticated = true and the name and Role is also correct, and the ticket is still valid.
This is the callstack
System.ArgumentNullException was unhandled by user code
HResult=-2147467261
Message=Key cannot be null.
Parameter name: key
Source=System
ParamName=key
StackTrace:
at System.Collections.Specialized.HybridDictionary.get_Item(Object key)
at System.Web.Security.RolePrincipal.IsInRole(String role)
at ASP._Page_Views_Admin_EditText_cshtml.Execute() in d:\SubVersion\Oline\Project1\Source\Oline.Portal\Views\Admin\EditText.cshtml:line 78
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
at System.Web.WebPages.StartPage.RunPage()
at System.Web.WebPages.StartPage.ExecutePageHierarchy()
at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
InnerException:
This is my Custom RoleProvier
public override string[] GetRolesForUser(string username)
{
var user = (string)HttpContext.Current.Session["UserRoles"];
var ret = new[] { user };
return ret;
}
The solution to the problem was, this section var user = (string)HttpContext.Current.Session["UserRoles"];, that becomes null. Special then I go back and fort, changing things in Visual Studio 2012. Thanks for the suggestions :)

Fluent NHibernate: One-to-many mapping to subclass where foreign key exists in abstract class

I'm new to using NHibernate/Fluent NHibernate and am trying to figure out how to use it with an existing database structure. I would like to get it working without changing the DB structure, if possible.
The database structure I'm trying to map loosely resembles:
Forms
----
FormId
CompletedBy
Records
-------
RecordId
RecordTypeId
FormId
EducationRecords
----------------
RecordId
SchoolName
DateAttendedFrom
DateAttendedTo
My entities:
public class Form
{
public virtual int Id { get; private set; }
public virtual string CompletedBy { get; set; }
public virtual IList<Entities.EducationRecord> EducationRecords { get; set; }
public Form()
{
this.EducationRecords = new List<EducationRecord>();
}
}
public abstract class Record
{
public virtual int Id { get; set; }
public virtual int RecordTypeId { get; set; }
public virtual Form Parent { get; set; }
}
public class EducationRecord : Record
{
public virtual string SchoolName { get; set; }
public virtual DateTime DateAttendedFrom { get; set; }
public virtual DateTime DateAttendedTo { get; set; }
}
My mappings:
public class FormMap : ClassMap<Entities.Form>
{
public FormMap()
{
Table("Forms");
Id(x => x.Id, "FormId");
Map(x => x.CompletedBy);
HasMany(x => x.EducationRecords);
}
}
public class RecordMap : ClassMap<Entities.Record>
{
public RecordMap()
{
Table("Records");
Id(x => x.Id, "RecordId");
Map(x => x.RecordTypeId);
References(x => x.Parent, "FormId");
}
}
public class EducationRecordMap : SubclassMap<Entities.EducationRecord>
{
public EducationRecordMap()
{
Table("EducationRecords");
KeyColumn("RecordId");
Map(x => x.SchoolName);
Map(x => x.DateAttendedFrom);
Map(x => x.DateAttendedTo);
}
}
With the way it is currently setup, I get the following exception when trying to access the EducationRecords property of Form:
[SqlException (0x80131904): Invalid column name 'FormId'.
Invalid column name 'FormId'.]
It looks like the underlying SQL query is trying to query against a 'FormId' column on the EducationRecords table, but that column does not exist there. I have spent a lot of time trying different variations of configurations with my map classes and have had no luck.
So my question is: How do I tell Fluent NHibernate to use the 'FormId' column in the Records table when retrieving Education records, or is this even possible?
Update:
My problem seems to essentially be the same as the one stated here (which, unfortunately, the question was never resolved):
Fluent NHibernate inheritance mapping problem
Update 2:
As suggested, I made the following change to FormMap:
HasMany(x => x.EducationRecords).Inverse();
But the same issue still occurs.
Here is the Source Error:
Line 14:
Line 15: <div>
Line 16: <% if (Model.EducationRecords.Any()) { %>
Line 17:
Line 18: <table>
The Model is of type Form.
Here is the stack trace:
[SqlException (0x80131904): Invalid column name 'FormId'.
Invalid column name 'FormId'.]
System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +2030802
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +5009584
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() +234
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2275
System.Data.SqlClient.SqlDataReader.ConsumeMetaData() +33
System.Data.SqlClient.SqlDataReader.get_MetaData() +86
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +311
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) +987
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) +162
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +32
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +141
System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader() +12
NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd) +278
NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session) +264
NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +186
NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies) +70
NHibernate.Loader.Loader.LoadCollection(ISessionImplementor session, Object id, IType type) +226
[GenericADOException: could not initialize a collection: [Sample.NHibernate.Entities.Form.EducationRecords#1][SQL: SELECT educationr0_.FormId as FormId1_, educationr0_.RecordId as RecordId1_, educationr0_.RecordId as RecordId1_0_, educationr0_1_.RecordTypeId as RecordTy2_1_0_, educationr0_1_.FormId as FormId1_0_, educationr0_.SchoolName as SchoolName2_0_, educationr0_.DateAttendedFrom as DateAtte3_2_0_, educationr0_.DateAttendedTo as DateAtte4_2_0_, educationr0_.Degree as Degree2_0_, educationr0_.DateDegreeAwarded as DateDegr6_2_0_ FROM dbo.EducationRecords educationr0_ inner join dbo.Records educationr0_1_ on educationr0_.RecordId=educationr0_1_.RecordId WHERE educationr0_.FormId=?]]
NHibernate.Loader.Loader.LoadCollection(ISessionImplementor session, Object id, IType type) +345
NHibernate.Loader.Collection.CollectionLoader.Initialize(Object id, ISessionImplementor session) +27
NHibernate.Persister.Collection.AbstractCollectionPersister.Initialize(Object key, ISessionImplementor session) +29
NHibernate.Event.Default.DefaultInitializeCollectionEventListener.OnInitializeCollection(InitializeCollectionEvent event) +349
NHibernate.Impl.SessionImpl.InitializeCollection(IPersistentCollection collection, Boolean writing) +431
NHibernate.Collection.AbstractPersistentCollection.Initialize(Boolean writing) +47
NHibernate.Collection.Generic.PersistentGenericBag`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +16
System.Linq.Enumerable.Any(IEnumerable`1 source) +71
ASP.views_form_index_aspx.__RenderContent2(HtmlTextWriter __w, Control parameterContainer) in c:\Dev\Sandbox\NHibernateSample\Sample.Web\Views\Form\Index.aspx:16
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +109
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +208
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
System.Web.UI.Control.Render(HtmlTextWriter writer) +10
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +208
System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8
System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +55
System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100
System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3060
In the generated SQL query shown in the GenericADOException, the WHERE clause specifies:
WHERE educationr0_.FormId=?
But it needs to be:
WHERE educationr0_1_.FormId=?
It has taken me a while to revisit this. I stopped playing with Fluent NHibernate shortly after posting this question.
Looking back, I think there may have been something fundamentally wrong with what I was trying to accomplish. My problem could be resolved simply by replacing the list of EducationRecords with Records. If needed, specific types of records could be retrieved from that.
I don't remember why I originally thought I needed a list of EducationRecords in Forms. I suspect it was either inexperience with ORMs on my part or there may have been a constraint that was not represented properly in the database design.
The solution really is very simple. You need to specify for all subclassmap, that is an abstract
base class
public class EducationRecordMap : SubclassMap<Entities.EducationRecord>
{
public EducationRecordMap()
{
Table("EducationRecords");
Abstract(); // because Record base class is abstract
KeyColumn("RecordId");
Map(x => x.SchoolName);
Map(x => x.DateAttendedFrom);
Map(x => x.DateAttendedTo);
}
}
Try to change:
HasMany(x => x.EducationRecords);
to
HasMany(x => x.EducationRecords).Inverse();
this way you are telling NH that only the child in this relationship is in charge of the saving.
You can read more about superfluous updates here:
http://nhprof.com/Learn/Alerts/SuperfluousManyToOneUpdate
You should check the resulting XML mappings. Maybe its generating subclass mapping instead of joined-subclass.
http://knol.google.com/k/fabio-maulo/nhibernate-chapter-8-inheritance-mapping/1nr4enxv3dpeq/11
Try this mapping:
public class FormMap : ClassMap<Entities.Form>
{
public FormMap()
{
Table("Forms");
Id(x => x.Id, "FormId");
Map(x => x.CompletedBy);
HasMany<Record>(x => x.EducationRecords).Where("form0_1_.EducationRecordId is not null");
}
}
And make class Record not abstract. This works for me. Maybe 'form0_1_' is not the correct column name. You can find the right one in the generated SQL.

No Persister for: error on save with INotifyPropertyChanged Interceptor

Using the method described in NHibernate & INotifyPropertyChanged, the repository will return a collection of proxies that implement INotifyPropertyChanged, but on some objects when saving or deleting it will throw an error:
at NHibernate.Impl.SessionFactoryImpl.GetEntityPersister(String entityName)
at NHibernate.Impl.SessionImpl.GetEntityPersister(String entityName, Object obj)
at NHibernate.Engine.ForeignKeys.IsTransient(String entityName, Object entity, Nullable`1 assumed, ISessionImplementor session)
at NHibernate.Event.Default.AbstractSaveEventListener.GetEntityState(Object entity, String entityName, EntityEntry entry, ISessionImplementor source)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj)
at MyCode ...
I figured out that if I create the session without the interceptor the SaveOrUpdate works fine, but with the interceptor it errors.
with the interceptor:
public ISession GetSession(ISessionFactory factory)
{
IInterceptor dataBinding = new DataBindingInterceptor {SessionFactory = factory};
return factory.OpenSession(dataBinding);
}
without
public ISession GetSession(ISessionFactory factory)
{
return factory.OpenSession();
}
I'm at a loss for how to go about even figuring out why the interceptor would break the save.
The only change I made to the code was changing the line
Type type = Type.GetType(clazz);
to
Type type = FindType(clazz);
public Type FindType(string typeName)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type foundType = assembly.GetType(typeName);
if (foundType != null)
return foundType;
}
return null;
}
Solution was to always use the session with the interceptor. I was creating the IList with the interceptor, but saving with a generic session. This bypassed the GetEntityName override which redirected the proxy to the correct persister.