EF6: Custom Proxy, good or bad idea? - c#

this issue arose for me when I had events which call multiple event handlers, but pass each one the same entity. Now, because entities are bound to one context in EF, passing the context along to the event handlers violated the one context per unit of work principle.
So the best I could come up with is a kind of factory and custom proxy (in this example only for Player, but I have more EF entities like Human, Participation, etc):
public class PlayerProxy : Player {
protected SnowbiteContext Context;
protected Player RealPlayer;
private long? _playerId;
private string _name;
public static Func<SnowbiteContext, PlayerProxy> NewProxyFactory(string name) =>
(ctx) => new PlayerProxy(ctx) {Name = name};
public static Func<SnowbiteContext, PlayerProxy> NewProxyFactory(long playerId) =>
(ctx) => new PlayerProxy(ctx) {PlayerId = playerId};
public PlayerProxy(SnowbiteContext ctx) {
Context = ctx ?? throw new ArgumentException();
}
public void Populate() {
if (RealPlayer != null) return;
if (_playerId != null) RealPlayer = Context.Players.Single(p => p.PlayerId == _playerId);
if (_name != null)
RealPlayer =
Context.Players.SingleOrDefault(p =>
p.Name == _name) ?? /* Contact external json API, complicated and expensive */;
}
public override long PlayerId {
get {
if (_playerId == null) Populate();
Debug.Assert(_playerId != null, nameof(_playerId) + " != null");
return _playerId.Value;
}
set {
Populate();
RealPlayer.PlayerId = value;
_playerId = null;
}
}
public override string Name {
get {
if (_name == null) Populate();
return _name;
}
set {
Populate();
RealPlayer.Name = value;
_name = null;
}
}
public override Human Human {
get {
Populate();
return RealPlayer.Human;
}
set {
Populate();
RealPlayer.Human = value;
}
}
public override long HumanId {
get {
Populate();
return RealPlayer.HumanId;
}
set {
Populate();
RealPlayer.HumanId = value;
}
}
public override ICollection<Participation> Participations {
get {
Populate();
return RealPlayer.Participations;
}
set {
Populate();
RealPlayer.Participations = value;
}
}
// Etc... for EaGuid, Tag, Rank.
}
Then the events would go like:
private void RCON_event_OnChat(IReadOnlyList<string> words) {
var name = words[1];
if (name == "Server") return;
EvChat?.Invoke(PlayerProxy.NewProxyFactory(name), words[2]);
}
And the event handlers (Player N:1 Human):
void Handler(Func<SnowbiteContext, PlayerProxy> playerProxyFactory, string message) {
using (var ctx = new SnowbiteContext()) {
PlayerProxy playerProxy = playerProxyFactory(ctx);
// use stuff, unit of work being done here, etc.
// but how about relating my proxy to other entities? Will EF handle my derived type correctly?
Human humanFromER = ctx.Humans.Single(/* ... */);
humanFromER.Players.Add(playerProxy);
playerProxy.Human = humanFromER;
// how about 1:N with ICollection<Participation>? Will EF recognize it properly?
playerProxy.Participations.Add(/* some new participation */);
}
}
For reference, here's my Player Entity:
public class Player {
public Player() {
Participations = new List<Participation>();
}
/// <summary>
/// BalzeId / PersonaId
/// </summary>
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public virtual long PlayerId { get; set; }
[Required]
public virtual long HumanId { get; set; }
public virtual Human Human { get; set; }
/// <summary>
/// Not a key. Mostly provided for convenicencet.
/// </summary>
[StringLength(35)]
public virtual string EaGuid { get; set; }
[Index]
[StringLength(60)]
public virtual string Name { get; set; }
[StringLength(4)]
public virtual string Tag { get; set; }
public virtual int Rank { get; set; }
public virtual ICollection<Participation> Participations { get; set; }
}
Or maybe just passing a string name to the event handler and having a simple function to get a player from the DB would have been simpler :D.
Update
Based on Gert Arnold's comment, I came up with this, getting rid of the proxy entirely:
private void RCON_event_OnChat(IReadOnlyList<string> words) {
var name = words[1];
if (name == "Server") return;
if (EvChat != null) {
// additionally, will be easy to convert to async
foreach (var handler in EvChat.GetInvocationList().Cast<Action<SnowbiteContext, Player, string>>()) {
using (var ctx = new SnowbiteContext()) {
var player = ctx.Players.SingleOrDefault(p => p.Name == name) ?? /* expensive resolve */;
handler(ctx, player, words[2]);
}
}
}
}

Related

C# Scripting with access to objects within application

Hello and still happy Ney Year
I would like to ask you for initial aid. My goal is to write a parser (e.g. source file is a bmecat-xml file and target is an Excel-file) that is dynamic and flexible enough to handle data-conversion even when sourcefile-content changes or user would require additional transformation of data.
I wrote the first part of the parser which loads data from the source-bmecat-file into corresponding classes. The class structure is exposed to the user (by reflection) and the user can map source-fields to target fields.
Where I get stuck is at the moment, when additional logic / conversion needs to be incorporated.
I think Scripting would help me to solve this. the mapping data (source field to target field) could contain an additional script that would be executed dynamically (and hence must have access to application data, especially classes which hold sourcefile and targetfile data).
It would be really great if you could point me to the right direction, to a point, where I can start from.
Thank you very much!
sample-code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace ScriptingDemoProject
{
class DataClass
{
TargetData target;
SourceData source;
MappingData map;
public DataClass()
{
target = new TargetData();
source = new SourceData();
map = new MappingData();
// generate sample data
GenerateData();
// copy source data to target data
ExecuteMapping();
}
public TargetData TargetDataInfo
{ get { return target; } }
public SourceData SourceDataInfo
{ get { return source; } }
public MappingData MappingDataInfo
{ get { return map; } }
private void GenerateData()
{
// add sourcedata
source.Header.DefaultLanguage = "deu";
source.RecipientID = "recipient...";
source.SenderID = "sender...";
SourceItem item = new SourceItem();
item.ItemID = "Item1";
item.ItemNames.AddRange( new List<SourceItemName>() {
new SourceItemName { ItemName = "Item1NameGerman", Languauge = "deu" },
new SourceItemName { ItemName = "Item1NameFrench", Languauge = "fra" }
});
source.Items.Add(item);
// add targetdata
target.AddRec(new List<TargetField>()
{
new TargetField { ColumnID=0, FieldName="ItemNo", FieldValue="Item1"},
new TargetField { ColumnID=1, FieldName="DescrGerman", FieldValue=""},
new TargetField { ColumnID=2, FieldName="DescrFrench", FieldValue=""}
});
target.AddRec(new List<TargetField>()
{
new TargetField { ColumnID=0, FieldName="ItemNo", FieldValue="Item2"},
new TargetField { ColumnID=1, FieldName="DescrGerman", FieldValue=""},
new TargetField { ColumnID=2, FieldName="DescrFrench", FieldValue=""}
});
// add mappinginstructions
map.TargetKeyFieldIndex = 0;
map.MappingFieldInfo.AddRange(new List<MappingFields>() {
new MappingFields { SourceFieldMapping="ItemName", TargetFieldMapping=1, ScriptMapping=#"... where Language=""ger""" },
new MappingFields { SourceFieldMapping="ItemName", TargetFieldMapping=2, ScriptMapping=#"... where Language=""fra""" }
});
// get properties, e.g.
var pInfo = source.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
}
private void ExecuteMapping()
{
// get target records
foreach (var targetRec in TargetDataInfo.TargetRecords)
{
// get key field value
string itemNo = targetRec.Where(x => x.ColumnID == map.TargetKeyFieldIndex).FirstOrDefault().FieldValue;
// get source item
SourceItem srcItem = SourceDataInfo.Items.Where(x => x.ItemID == itemNo).FirstOrDefault();
if (srcItem == null)
continue;
// get mapping instructions
foreach (var mapInstruction in map.MappingFieldInfo)
{
// i'd like to have two options
// option 1: use script
// option 2: use reflection
// option 1: script
// script will be executed at runtime and gets value from srcItem and sets value in targetRec
string script = mapInstruction.ScriptMapping;
// script would contain / execute the following statements:
TargetField field = targetRec.Where(x => x.ColumnID == mapInstruction.TargetFieldMapping).FirstOrDefault();
field.FieldValue = srcItem.ItemNames.Where(x => x.Languauge == "deu").FirstOrDefault().ItemName;
// option 2: get value by reflection
// e.g.
// though don't know how to handle List<Class>
PropertyInfo pi = SourceDataInfo.GetType().GetProperty("SenderID");
object val = pi.GetValue(SourceDataInfo, null);
// ...
}
}
}
}
public class MappingData
{
List<MappingFields> mappingFields;
public MappingData ()
{
mappingFields = new List<MappingFields>();
}
public int TargetKeyFieldIndex { get; set; }
public List<MappingFields> MappingFieldInfo
{ get { return mappingFields; } }
}
public class MappingFields
{
public string SourceFieldMapping { get; set; }
public int TargetFieldMapping { get; set; }
public string ScriptMapping { get; set; }
}
public class TargetData
{
private List<List<TargetField>> targetRecords;
public TargetData()
{
targetRecords = new List<List<TargetField>>();
}
public List<List<TargetField>> TargetRecords
{ get { return targetRecords; } }
public void AddRec(List<TargetField> TargetFields)
{
targetRecords.Add(TargetFields);
}
}
public class TargetField
{
public string FieldName
{ get; set; }
public int ColumnID
{ get; set; }
public string FieldValue
{ get; set; }
}
public class SourceData
{
private List<SourceItem> sourceItems;
private SourceHeader sourceHeader;
public SourceData()
{
sourceHeader = new SourceHeader();
sourceItems = new List<SourceItem>();
}
public SourceHeader Header
{ get { return sourceHeader; } }
public List<SourceItem> Items
{ get { return sourceItems; } }
public string SenderID
{ get; set; }
public string RecipientID
{ get; set; }
}
public class SourceHeader
{
public string DefaultLanguage
{ get; set; }
}
public class SourceItem
{
private List<SourceItemName> itemNames;
public SourceItem()
{
itemNames = new List<SourceItemName>();
}
public string ItemID
{ get; set; }
public List<SourceItemName> ItemNames
{ get { return itemNames; } }
public SourceItemName GetNameByLang(string Lang)
{
return itemNames.Where(x => x.Languauge == Lang).FirstOrDefault();
}
}
public class SourceItemName
{
public string ItemName
{ get; set; }
public string Languauge
{ get; set; }
}
}

The advice on the simplification of the functions

I have an entity Contracts like this:
public partial class Contracts
{
public Contracts()
{
ListKindWorks = new HashSet<ListKindWorks>();
ListSubjects = new HashSet<ListSubjects>();
}
public int Id { get; set; }
public string Num { get; set; }
public DateTime DateConclusion { get; set; }
public int Worker { get; set; }
public DateTime DateStartWork { get; set; }
public DateTime DateEndWork { get; set; }
public float Salary { get; set; }
public virtual Workers WorkerNavigation { get; set; }
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
public virtual ICollection<ListSubjects> ListSubjects { get; set; }
}
And function ShowUpdateDialog():
/// <summary>
/// Open dialog for update chosen Contract
/// </summary>
/// <param name="c">chosen Contract</param>
internal void ShowUpdateDialog(Contracts c)
{
Contract = c;
using (ContractForm form = new ContractForm())
{
form.Fill(model.Data);
form.Fill(Contract);
form.Fill(model.GetUI(Mode.UPDATE));
if (form.ShowDialog() == DialogResult.OK)
{
bool result = true;
try
{
using (ModelContext context = new ModelContext())
{
context.Attach(Contract);
Contract = form.GetMainValues(Contract);
Contract = form.GetDetailValues(Contract);
context.SaveChanges();
}
}
catch (Exception ex)
{
result = false;
string msg = string.Format("Ошибка во время обновления записи в базе данных. Детали: {0}", ex.Message);
form.ShowError(msg);
}
if (result)
{
ContractUpdatedSuccessEvent?.Invoke(this, EventArgs.Empty);
}
}
}
}
External variable:
public Contracts Contract { get; set; }
It is used not to allocate memory every time and is public, so that in case of a successful update another class can take it and insert into the DataGridView. Therefore I'm not accessing the database for the current values of the record, because the data comes from the DataGridView. To track changes used context.Attach(Contract).
internal Contracts GetMainValues(Contracts c)
{
c.Num = tbNum.Text;
c.Salary = float.Parse(tbSalary.Text);
c.DateConclusion = dpDateConclusion.Value;
c.DateStartWork = dpDateStart.Value;
c.DateEndWork = dpDateEnd.Value;
Item item = (Item)cbWorker.SelectedItem;
c.Worker = item.Id;
return c;
}
internal Contracts GetDetailValues(Contracts c)
{
listKindWorks.Clear();
listSelectedSubjects.Clear();
foreach (int index in clbKindWork.CheckedIndices)
{
int id = ((Item)clbKindWork.Items[index]).Id;
ListKindWorks item = new ListKindWorks
{
IdContract = c.Id,
IdKindWork = id
};
listKindWorks.Add(item);
}
foreach (Item item in lbSelectedSubject.Items)
{
ListSubjects subject = new ListSubjects
{
IdContract = c.Id,
IdSubject = item.Id
};
listSelectedSubjects.Add(subject);
}
c.ListKindWorks = listKindWorks;
c.ListSubjects = listSelectedSubjects;
return c;
}
My problem is as follows:
When if (.. == DialogResult.OK) is true, I need to update current Contract to new values from a form like this:
context.Attach(Contract);
Contract = form.GetMainValues(Contract);
Contract = form.GetDetailValues(Contract);
context.SaveChanges();
But therefore this code must be into using (ContractForm..). Otherwise impossible to get new values from form. If I create a new variable like Contracts and separate function Update like this:
private void Update(Contracts c)
{
using (ModelContext context = new ModelContext())
{
context.Attach(Contract);
Contract = c;
context.SaveChanges();
}
}
No update occurs for values from GetDetailValues(). Why?
Can I simplify this code?
Update:
According code from answer Henk Holterman and my private void Update(Contracts c):
changed values from GetMainValues(), but no from GetDetailValues()
I added to Contracts method Update() and call it after .Attach()
internal void Update(Contracts c)
{
this.Num = c.Num;
this.Salary = c.Salary;
this.Worker = c.Worker;
this.FullName = c.FullName;
this.DateConclusion = c.DateConclusion;
this.DateStartWork = c.DateStartWork;
this.DateEndWork = c.DateEndWork;
this.ListKindWorks = c.ListKindWorks;
this.ListSubjects = c.ListSubjects;
}
private void Update(Contracts oldValue, Contracts newValue)
{
using (ModelContext context = new ModelContext())
{
context.Attach(oldValue);
oldValue.Update(newValue);
// oldValue = newValue; // .Attach does not respond to this
context.SaveChanges();
}
}

linq update not working

I have tried a lot but all in vain.
I have written a LINQ code but not able to save changes in database.
It is giving no error neither it is updating record.
class Program
{
[Table(Name = "mainframe_replication")]
public class mainframe_replication
{
private string _REPL_GUID;
[Column(IsPrimaryKey = true, Storage = "_REPL_GUID")]
public string REPL_GUID
{
get { return this._REPL_GUID; }
set { this._REPL_GUID = value; }
}
private string _REPL_TYPE;
[Column(Storage = "_REPL_TYPE")]
public string REPL_TYPE
{
get { return this._REPL_TYPE; }
set { this._REPL_TYPE = value; }
}
private string _RPT_ID;
[Column(Storage = "_RPT_ID")]
public string RPT_ID
{
get { return this._RPT_ID; }
set { this._RPT_ID = value; }
}
private string _RPT_VERS;
[Column(Storage = "_RPT_VERS")]
public string RPT_VERS
{
get { return this._RPT_VERS; }
set { this._RPT_VERS = value; }
}
private string _RPT_BYTES;
[Column(Storage = "_RPT_BYTES")]
public string RPT_BYTES
{
get { return this._RPT_BYTES; }
set { this._RPT_BYTES = value; }
}
private string _REPL_DTM;
[Column(Storage = "_REPL_DTM")]
public string REPL_DTM
{
get { return this._REPL_DTM; }
set { this._REPL_DTM = value; }
}
private string _NOTIF_ID;
[Column(Storage = "_NOTIF_ID")]
public string NOTIF_ID
{
get { return this._NOTIF_ID; }
set { this._NOTIF_ID = value; }
}
}
public class MyPoco
{
public string ReportId { get; set; }
public string Reportversion { get; set; }
public string ReportBytes { get; set; }
public string ReportDate { get; set; }
public string NotifId { get; set; }
public string RecipAdd { get; set; }
}
public static string loglocation;
static void Main(string[] args)
{
try
{
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID, (mfr, nr)
=> new MyPoco { ReportId = mfr.RPT_ID, Reportversion = mfr.RPT_VERS, ReportBytes = mfr.RPT_BYTES.ToString(), ReportDate = mfr.REPL_DTM.ToString(), NotifId = mfr.NOTIF_ID, RecipAdd = nr.NOTIF_RECIP_ADDR });
foreach (var repljoinmf_data in repljoinmf)
{
repljoinmf_data.NotifId = "abc";
//DO STUFF
// repljoinmf_data.NotifId = "Changedxyz";
}
db.SubmitChanges();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
It is not giving any error while submitting changes.
What I need to change?
Any suggestion will be helpful.
If you want to save your changes back to the original data source, you need to be working with the actual entities instead of projections of those entities. Since you are joining two tables, one option is to put those instances into an anonymous type and update them:
foreach (string notif_sched_data in ids)
{
var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias,
mfr => mfr.RPT_ID,
nr => nr.NOTIF_RECIP_ID,
(mfr, nr) => new {mfr, nr});
foreach (var repljoinmf_data in repljoinmf)
{
//DO STUFF
repljoinmf_data.mfr.NotifId = "Changedxyz";
}
db.SubmitChanges();
In your previous question you were told that anonymous types cannot be uptated, but in this case you're modifying instances that are referenced by the anonymous type. So you're not updating the anonymous type itself, just the objects that the anonymous type references.
You are modifying the property of your MyPoco object. This is just a representation of your table. That's why the database is not updated.
You can send your MyPoco to your client. It will perform some changes. Then you can recreate the entity and copy the properties from the Poco object. Then, you need to attach the modified entity to your table and then save the changes.
If you modify directly the entity, there is no need to attach, since it will have kept the links to the database (assuming you do that with the same Databasecontext).

EF Lazy loading not working

Entity and Component has one-to-many relationship. Entity stored in db correctly, with all components. But when I trying load it back this Entity in Child method Components not loads. If i try use lazy loading, code failing on entity.GetComponent because of Entity.Components isn't initialized. After exception Components are initialized and has zero elements. If I disable lazy loading, Components are initialized and has zero elements. I wrote example for building one-to-many relationship and using lazy initialization, and it works fine.
public static void Main(string[] args)
{
Parent();
Child();
}
private static void Child()
{
using (var db = new EntitiesContext())
{
var entities = from entity in db.Entities
select entity;
foreach (Entity entity in entities)
{
Position pos = entity.GetComponent<Position>();
Core core = entity.GetComponent<Core>();
}
}
}
private static void Parent()
{
Entity entity = new Entity();
entity.AddComponent(new Position(10, 10));
entity.AddComponent(new ObjectName("Entity" + 1));
entity.AddComponent(new Core(100));
using (var db = new EntitiesContext())
{
db.Entities.Add(entity);
db.SaveChanges();
}
}
public class EntitiesContext : DbContext
{
public DbSet<TypeMaskPair> MappedTypes { get; set; }
public DbSet<Entity> Entities { get; set; }
public EntitiesContext()
: base("EntitiesDb")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>()
.HasMany(entity => entity.Components)
.WithRequired(component => component.EntityObj)
.HasForeignKey(component => component.EntityId)
.WillCascadeOnDelete();
//this.Configuration.LazyLoadingEnabled = false;
}
}
public abstract class Component
{
[Key]
public int Id { get; set; }
[Required]
public int EntityId { get; set; }
[Required]
public virtual Entity EntityObj { get; set; }
private static DbMasksMapper componentsMap;
static Component()
{
componentsMap = new DbMasksMapper(typeof(Component));
}
public TypeMask GetMask()
{
return componentsMap.GetMask(this.GetType());
}
public static TypeMask GetMask<T>() where T : Component
{
return componentsMap.GetMask(typeof(T));
}
}
public class Entity
{
[Key]
public int Id { get; set; }
public virtual List<Component> Components { get; set; }
[NotMapped]
public TypeMask Mask { get; private set; }
public string TypeMaskString
{
get{ return Mask.ToString(); }
set{ Mask = new TypeMask(value); }
}
public Entity()
{
Components = new List<Component>();
Mask = new TypeMask();
}
public void AddComponent(Component component)
{
Components.Add(component);
component.EntityObj = this;
Mask |= component.GetMask();
}
public void DeleteComponent(TypeMask componentMask)
{
if (ContainsComponent(componentMask))
{
int removeIndex = Components.FindIndex(c => c.GetMask() == componentMask);
Components.RemoveAt(removeIndex);
Mask &= ~componentMask;
}
}
public Component GetComponent(TypeMask componentMask)
{
return Components.Find(c => c.GetMask() == componentMask);
}
public T GetComponent<T>() where T : Component
{
return (T) GetComponent(Component.GetMask<T>());
}
public bool ContainsComponent<T>() where T : Component
{
return ContainsComponent(Component.GetMask<T>());
}
public bool ContainsComponent(TypeMask componentMask)
{
return (Mask & componentMask) == componentMask;
}
}
class Position : Component
{
public Position(int x = 0, int y = 0)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
}
class Cargo : Component
{
public Cargo(int capacity = 0)
{
Capacity = capacity;
}
public int Capacity { get; set; }
}
class Core : Component
{
public Core(int power = 0)
{
Power = power;
}
public int Power { get; set; }
}
class ObjectName : Component
{
public ObjectName(string name = "")
{
Name = name;
}
public string Name { get; set; }
}
I saw similar questions, but didn't found any answer.
Where is a mistake?
Solution
All works after I wrote default constructor for inherited components. But, I don't understand why constructor with default arguments doesn't suitable. Without any argument it should work like default constructor. Can anyone explain it? Seems I doing it wrong

Can't delete last item from nhibernate model (cascading issue)

Based on this mappings: nhibernate criteria for selecting from different tables
If I want to delete the last Model.Order I get this error message:
"deleted object would be re-saved by cascade (remove deleted object from associations"
Here my code:
Model.Unit unitToDelete = m_MainGUI.Manager.RetrieveEquals<Model.Unit>("ID", unitID)[0];
Model.Order currentOrder = m_MainGUI.Manager.RetrieveEquals<Model.Order>("ID", unitToDelete.OrderRef.ID)[0];
if (currentOrder.Units.Count == 1) // last unit of order
{
// delete references
unitToDelete.OrderRef = null;
unitToDelete.EmployeeRef = null;
currentOrder.Units.Remove(unitToDelete); // remove unit from collection
m_MainGUI.Manager.Delete<Model.Unit>(unitToDelete);
m_MainGUI.Manager.Delete<Model.Order>(currentOrder); <---- ERROR
}
else
{
currentOrder.Units.Remove(unitToDelete); // remove unit from collection
m_MainGUI.Manager.Save<Model.Order>(currentOrder); // update order with removed unit
}
My delete method
public void Delete<T>(T item)
{
using (m_HibernateSession.BeginTransaction())
{
m_HibernateSession.Delete(item);
m_HibernateSession.Transaction.Commit();
m_HibernateSession.Flush();
}
}
Unit.cs (parts of them)
public virtual Employee EmployeeRef { get; set; }
public virtual Order OrderRef { get; set; }
public virtual string Employee
{
get
{
if (EmployeeRef != null) return EmployeeRef.Name;
else return "";
}
}
public virtual int PONumber
{
get
{
return OrderRef.PONumber;
}
}
public virtual int OrderID
{
get
{
return OrderRef.ID;
}
}
Order.cs (parts of them)
private IList<Unit> m_UnitsList = new List<Unit>();
public virtual IList<Unit> Units
{
get { return m_UnitsList; }
set { m_UnitsList = value; }
}
public virtual string Distributor
{
get
{
if (Units.Count != 0) return Units[0].Distributor;
return "";
}
}
public virtual string Department
{
get
{
if (Units.Count != 0) return Units[0].Department;
return "";
}
}
Any hints whats wrong?
Thx
I would bet that you have reference to Order from Unit, so you need to do Unit.Order = null.

Categories

Resources