using System;
using System.Collections;
using System.Collections.Generic;
using Kreta.Framework.Util;
namespace Kreta.Framework.Entities
{
///
/// Az entitások absztrakt ősosztálya.
///
public abstract class Entity
{
// <>
//private static Hashtable m_EntityAttributeCache = Hashtable.Synchronized(new Hashtable());
protected int m_ID;
protected EntityState m_State;
protected int m_Serial;
protected DateTime? m_EntityLastChanged = null;
protected DateTime? m_EntityCreated = null;
protected bool m_Torolt = false;
protected int? m_EntityModifier = null;
protected int m_EntityCreator = -1;
private Hashtable m_OriginalValues = new Hashtable();
private Hashtable m_CurrentValues = new Hashtable();
///
/// Az osztály alapértelmezett konstruktora.
///
protected Entity()
{
}
#region Belső dolgok
///
/// Ellenőrzi, hogy az entitás módosítható állapotban van.
///
/// Ha nem módosítható az entitás
protected void CheckModifyable()
{
if (!CanModifyFields)
{
throw new EntityStateException(m_State);
}
}
///
/// Alapállapotba állítja az objektumot
///
protected virtual void Reset()
{
m_State = EntityState.Uninitialized;
m_ID = -1;
m_Serial = -1;
m_EntityCreated = null;
m_EntityCreator = -1;
m_EntityLastChanged = null;
m_Torolt = false;
m_EntityModifier = null;
m_CurrentValues.Clear();
m_OriginalValues.Clear();
}
///
/// Visszaadja az entitás adatbázisműveleteit végző objektumát.
///
/// Az entitás adatbázisműveleteit végző objektum
protected abstract IEntityDataAccessor GetDataAccessor();
#endregion
#region Nyilvános felület
///
/// Visszaadja az entitás nevét.
///
///
/// Az entitás nevét a rajta lévő attribútum definiálja.
/// A névnek rendszer szinten egyedinek kell lennie.
///
public string GetEntityName()
{
return EntityAttributeCache.GetEntityNameFromCache(GetType());
}
///
/// Az entitás azonosítója
///
/// Az entitást azonosító nemnegatív egész szám
public int ID
{
get
{
return m_ID;
}
set
{
m_ID = value;
}
}
///
/// Az entitás utolsó módosításának ideje
///
public virtual DateTime? EntityLastChanged
{
get
{
return m_EntityLastChanged;
}
internal protected set
{
m_EntityLastChanged = value;
}
}
///
/// Az entitás létrehozásának ideje
///
public virtual DateTime? EntityCreated
{
get
{
return m_EntityCreated;
}
internal protected set
{
m_EntityCreated = value;
}
}
///
/// Az entitás létrehozójának adatai
///
public virtual int EntityCreator
{
get
{
return m_EntityCreator;
}
internal protected set
{
m_EntityCreator = value;
}
}
///
/// Az entitás logikailag törölve van.
///
public virtual bool Torolt
{
get
{
return m_Torolt;
}
set
{
m_Torolt = value;
}
}
///
/// Az entitás módosítójának adatai
///
public virtual int? EntityModifier
{
get
{
return m_EntityModifier;
}
internal protected set
{
m_EntityModifier = value;
}
}
///
/// Az entitás verziója
///
/// Az entitás verziója
/// Az entitás verziója kezdetben nulla, és minden mentésnél eggyel no.
public int Serial
{
get
{
return m_Serial;
}
set
{
m_Serial = value;
}
}
///
/// Az entitás jelenlegi állapota.
///
public EntityState State
{
get
{
return m_State;
}
set
{
SetState(value);
}
}
///
/// Új állapotba hozza az entitást.
///
/// Új állapot
public void SetState(EntityState state)
{
m_State = state;
}
///
/// Betöltött állapotba helyezi az entitást.
///
public void SetLoaded()
{
m_State = EntityState.Initialized;
StoreOriginalValues();
}
///
/// Ellenőrzi, hogy az entitás attribútumai érvényes értékeket tartalmaznak-e.
///
///
/// Ha valamelyik attribútum értéke érvénytelen.
///
protected virtual void Validate(bool skipValidateAttributes = false)
{
// Az ősosztályban nem kell csinálnunk semmit.
}
#endregion
#region Állapottal kapcsolatos dolgok
///
/// Visszaadja, hogy az entitás be van-e már töltve.
///
public bool IsInitialized
{
get
{
return (m_State == EntityState.Initialized || m_State == EntityState.Modified);
}
}
///
/// Visszaadja, hogy az entitás módosítva lett-e.
///
public bool IsModified
{
get
{
return (m_State == EntityState.Modified);
}
}
///
/// Visszaadja, hogy az entitás törölve lett-e.
///
public bool IsDeleted
{
get
{
return (m_State == EntityState.Removed);
}
}
///
/// Ellenőrzi, hogy az entitás állapota megfelelő-e a betöltés művelethez.
///
/// True, ha az entitás betölthető; egyébként false
protected bool CanLoad
{
get
{
return (m_State == EntityState.Uninitialized);
}
}
///
/// Ellenőrzi, hogy az entitás állapota megfelelő-e a beszúrás művelethez.
///
/// True, ha az entitás beszúrható az adatbázisba; egyébként false
protected bool CanInsert
{
get
{
return (m_State == EntityState.New || m_State == EntityState.Uninitialized);
}
}
///
/// Ellenőrzi, hogy az entitás állapota megfelelő-e a módosítás művelethez.
///
/// True, ha az entitás módosítható az adatbázisban; egyébként false
protected bool CanUpdate
{
get
{
return (m_State == EntityState.Modified || m_State == EntityState.Initialized);
}
}
///
/// Ellenőrzi, hogy az entitás állapota megfelelő-e a törléshez.
///
/// True, ha az entitás törölhető az adatbázisban; egyébként false
protected bool CanRemove
{
get
{
return (m_State != EntityState.Uninitialized);
}
}
///
/// Ellenőrzi, hogy az entitás állapota megfelelő-e az attribútumainak módosításához.
///
/// True, ha az entitás attribútumai módosíthatóak; egyébként false
protected bool CanModifyFields
{
get
{
return (m_State != EntityState.Removed);
}
}
#endregion
#region CRUD logika
///
/// Azonosító alapján feltölti az entitást az adatbázisból
///
/// Az entitás azonosítója
/// True, ha sikeres; egyébként False
public bool LoadEntityByID(int id)
{
if (m_State != EntityState.Uninitialized)
{
throw new EntityStateException(m_State);
}
m_ID = id;
if (!GetDataAccessor().LoadEntity(this, id))
{
m_ID = -1;
return false;
}
return true;
}
///
/// Azonosító alapján feltölti az entitást az adatbázisból, minden oszloppal
///
/// Az entitás azonosítója
/// Ha a megadott azonosítójú entitás nem található.
public void LoadByID(int id)
{
if (m_State != EntityState.Uninitialized)
{
throw new EntityStateException(m_State);
}
m_ID = id;
if (!GetDataAccessor().LoadEntity(this, id))
{
m_ID = -1;
throw new EntityNotFoundException(GetEntityName(), id);
}
}
///
/// Azonosító alapján feltölti az entitást az adatbázisból, tiltó oszlopszűréssel
///
/// Az entitás azonosítója
/// A betöltésre nem kerülő oszlopok
public void LoadByID(int id, IEnumerable filteredColumns)
{
this.LoadByID(id, ColumnFilterMode.DEFAULT_ALLOWED, filteredColumns);
}
///
/// Azonosító alapján feltölti az entitást az adatbázisból, oszlopszűréssel
///
/// Az entitás azonosítója
/// A szűrés módja, megengedő vagy tiltó
/// A szűrendő oszlopok felsorolása
public void LoadByID(int id, ColumnFilterMode columnFilterMode, IEnumerable columns)
{
if (m_State != EntityState.Uninitialized)
{
throw new EntityStateException(m_State);
}
m_ID = id;
if (!GetDataAccessor().FilteredLoadEntity(this, id, columnFilterMode, columns))
{
m_ID = -1;
throw new EntityNotFoundException(GetEntityName(), id);
}
}
///
/// Azonosító alapján feltölti az entitást adatbázisból.
///
/// Az entitás azonosítója
/// Az entitás verziószáma
/// Ha az entitás verziószáma nem egyezik a megadottal.
/// Ha a megadott azonosítójú entitás nem található.
public void LoadByID(int id, int serial)
{
LoadByID(id);
if (m_Serial != serial)
{
throw new EntityExpiredException(GetEntityName(), ID, m_Serial, serial);
}
}
///
/// Azonosító alapján feltölti az entitást adatbázisból, oszlopszűréssel
///
///
///
///
///
public void LoadByID(int id, int serial, ColumnFilterMode columnFilterMode, IEnumerable columns)
{
LoadByID(id, columnFilterMode, columns);
if (m_Serial != serial)
{
throw new EntityExpiredException(GetEntityName(), ID, m_Serial, serial);
}
}
///
/// Adatbázisba menti a még nem létező entitást.
///
public void Insert()
{
Insert(true);
}
///
/// Adatbázisba menti a még nem létező entitást.
///
/// Futtassa-e a hozzá tartozó objektumot, vagy sem
public void Insert(bool runHandler)
{
try
{
// <>
IEntityHandler handler = null;
if (runHandler)
{
handler = EntityHandler.Create(GetType());
handler.BeforeInsert(this);
}
DoInsert();
if (runHandler)
{
handler.AfterInsert(this);
}
}
catch
{
EntityState es = this.State;
this.State = EntityState.New; // biztos ami biztos
this.StoreOriginalValues(); // hogy legyen mit logolni
//EntityHistoryLogger.LogErrorHistory(this);
this.State = es;
throw;
}
}
///
/// Adatbázisba menti a már létező entitás tulajdonságait.
///
public void Update()
{
Update(true);
}
///
/// Adatbázisba menti a már létező entitás tulajdonságait.
///
/// Futtassa-e a hozzá tartozó objektumot, vagy sem
public void Update(bool runHandler)
{
try
{
// <>
IEntityHandler handler = null;
if (runHandler)
{
handler = EntityHandler.Create(GetType());
handler.BeforeUpdate(this);
}
DoUpdate(true, false);
if (runHandler)
{
handler.AfterUpdate(this);
}
}
catch
{
EntityState es = this.State;
this.State = EntityState.Modified; // különben nem logol
//EntityHistoryLogger.LogErrorHistory(this);
this.State = es;
throw;
}
}
///
/// Adatbázisba menti az entitás asszociációit.
///
/// Valójában csak azokat, amelyeknél a kapcsolómező ennek az entitásnak a táblájában van!
public void UpdateAssociations()
{
UpdateAssociations(true);
}
///
/// Adatbázisba menti az entitás asszociációit.
///
/// Futtassa-e a hozzá tartozó objektumot, vagy sem
/// Valójában csak azokat, amelyeknél a kapcsolómező ennek az entitásnak a táblájában van!
public void UpdateAssociations(bool runHandler)
{
try
{
// <>
IEntityHandler handler = null;
if (runHandler)
{
handler = EntityHandler.Create(GetType());
handler.BeforeUpdate(this);
}
DoUpdate(false, true);
if (runHandler)
{
handler.AfterUpdate(this);
}
}
catch
{
EntityState es = this.State;
this.State = EntityState.Modified; // különben nem logol
//EntityHistoryLogger.LogErrorHistory(this);
this.State = es;
throw;
}
}
///
/// Adatbázisba menti a már létező entitás tulajdonságait és asszociációit.
///
public void FullUpdate()
{
FullUpdate(true);
}
///
/// Adatbázisba menti a már létező entitás tulajdonságait és asszociációit.
///
/// Futtassa-e a hozzá tartozó objektumot, vagy sem
public void FullUpdate(bool runHandler)
{
try
{
// <>
IEntityHandler handler = null;
if (runHandler)
{
handler = EntityHandler.Create(GetType());
handler.BeforeUpdate(this);
}
DoUpdate(true, true);
if (runHandler)
{
handler.AfterUpdate(this);
}
}
catch
{
EntityState es = this.State;
this.State = EntityState.Modified; // különben nem logol
//EntityHistoryLogger.LogErrorHistory(this);
this.State = es;
throw;
}
}
///
/// Törli az entitást az adatbázisból.
///
/// Sikeres törlés esetén az entitás 'EntityState.REMOVED' állapotba kerül.
public void Delete(bool logikai = true)
{
Delete(true, logikai);
}
///
/// Leellenőrzi az aktív kapcsolatait törléshez.
///
void CheckActiveConnections()
{
var entityNames = new List() { GetEntityName() };
var entityType = this.GetType();
if (entityType.BaseType != typeof(Entity))
{
entityNames.Add(EntityAttributeCache.GetEntityNameFromCache(entityType.BaseType));
}
var EntitasKapcsolatok = EntityUtils.GetEntitiesConnections(new List() { this.ID }, entityNames);
// ha van az entitásnak kapcsolata, akkor elszáll
if (EntitasKapcsolatok.Count > 0 && EntitasKapcsolatok[ID].Count > 0)
{
throw new EntityDeleteFailedException(StringResourcesUtil.GetString(3478), EntitasKapcsolatok[ID]);
}
}
///
/// Törli az entitást az adatbázisból.
///
/// Futtassa-e a hozzá tartozó objektumot, vagy sem
public void Delete(bool runHandler, bool logikai = true)
{
try
{
// <>
IEntityHandler handler = null;
if (runHandler)
{
handler = EntityHandler.Create(GetType());
handler.BeforeDelete(this);
}
// ellenőrzi az aktív kapcsolatait
CheckActiveConnections();
DoDelete(false, runHandler, logikai);
if (runHandler)
{
handler.AfterDelete(this);
}
}
catch /*(Exception ex)*/
{
EntityState es = this.State;
this.State = EntityState.Removed; // biztos ami biztos
//EntityHistoryLogger.LogErrorHistory(this);
this.State = es;
throw;
}
}
///
/// Törli az entitást az adatbázisból a kapcsolódásaival együtt.
///
/// Sikeres törlés esetén az entitás 'EntityState.REMOVED' állapotba kerül.
public void CascadeDelete(bool logikai = true)
{
CascadeDelete(false, logikai);
}
///
/// Törli az entitást az adatbázisból a kapcsolódásaival együtt.
///
/// Futtassa-e a hozzá tartozó objektumot, vagy sem
public void CascadeDelete(bool runHandler, bool logikai = true)
{
try
{
// <>
IEntityHandler handler = null;
if (runHandler)
{
handler = EntityHandler.Create(GetType());
handler.BeforeDelete(this);
}
DoDelete(true, runHandler);
if (runHandler)
{
handler.AfterDelete(this);
}
}
catch
{
EntityState es = this.State;
this.State = EntityState.Removed; // biztos ami biztos
//EntityHistoryLogger.LogErrorHistory(this);
this.State = es;
throw;
}
}
///
/// Elvégzi az entitás törlése előtti szétkapcsolásokat és kaszkád törléseket.
///
protected virtual void DeAssociateBeforeDelete(bool runHandler = false)
{
// Az ősosztályban nem kell csinálnunk semmit.
}
///
/// Elvégzi az entitás törlését.
///
/// Kaszkádosított törlés legyen-e, vagy sem
protected virtual void DoDelete(bool performCascadeDelete, bool runHandler = false, bool logikai = true)
{
if (!CanRemove)
{
throw new EntityStateException(m_State);
}
if (performCascadeDelete)
{
DeAssociateBeforeDelete(runHandler);
}
GetDataAccessor().DeleteEntity(this, logikai);
SetState(EntityState.Removed);
//EntityHistoryLogger.LogHistory(this);
}
///
/// elvegzi az entitás update-jet
///
protected virtual void DoUpdate(bool withattributes, bool withassociations)
{
if (!CanUpdate)
{
throw new EntityStateException(m_State);
}
Validate(!withattributes);
if (withattributes)
{
if (!GetDataAccessor().UpdateEntity(this))
{
throw new EntityExpiredException(GetEntityName(), ID, m_Serial);
}
}
if (withassociations)
{
if (!GetDataAccessor().UpdateAssociations(this))
{
throw new EntityExpiredException(GetEntityName(), ID, m_Serial);
}
}
//EntityHistoryLogger.LogHistory(this);
SetState(EntityState.Initialized);
}
///
/// elvegzi az entitas insertjet
///
protected virtual void DoInsert()
{
if (!CanInsert)
{
throw new EntityStateException(m_State);
}
Validate();
GetDataAccessor().InsertEntity(this);
StoreOriginalValues();
//EntityHistoryLogger.LogHistory(this);
SetState(EntityState.Initialized);
}
#endregion
#region Oszlopszintű naplózás támogatása
///
/// Eltárolja az entitás összes attribútumának adatbázisban tárolt értékét.
///
protected virtual void StoreOriginalValues()
{
m_OriginalValues.Clear();
}
///
/// A függvény eltárolja egy attribútum értékének megváltozását.
///
/// A módosult attribútum neve
/// A módosult attribútum új értéke
/// Ezt a metódust meg kell hívni minden olyan esetben, amikor olyan attribútum módosult,
/// amelyet oszlop szinten naplózni kell.
protected void FieldModified(string attributeName, object value)
{
if (string.IsNullOrWhiteSpace(attributeName))
{
throw new ArgumentNullException(nameof(attributeName));
}
if (m_State == EntityState.Initialized)
{
SetState(EntityState.Modified);
}
else if (m_State == EntityState.Uninitialized)
{
SetState(EntityState.New);
}
m_CurrentValues[attributeName] = (value ?? DBNull.Value);
}
///
/// Az entitás eredeti naplózandó attribútumai.
///
protected internal Hashtable OriginalValues
{
get
{
return m_OriginalValues;
}
}
///
/// Az entitás módosult naplózandó attribútumai a jelenlegi értékükkel.
///
protected internal Hashtable CurrentValues
{
get
{
return m_CurrentValues;
}
}
///
/// Visszaadja egy attribútum eredeti értékét.
///
/// Az attribútum neve
/// Az attribútum eredeti értéke
/// Ha az entitás nem rendelkezik a magadott attribútummal, vagy az nem naplózandó.
public object GetOriginalValue(string attributeName)
{
if (!m_OriginalValues.ContainsKey(attributeName))
{
throw new ArgumentException("The entity does not contain the original value for the specified attribute.", nameof(attributeName));
}
object result = m_OriginalValues[attributeName];
if (result == DBNull.Value)
{
return null;
}
return result;
}
///
/// Megvizsgálja, hogy egy attribútum eredeti értéke null-e, vagy sem.
///
/// Az attribútum neve
/// True, ha az attribútum eredeti értéke null; egyébként false
/// Ha az entitás nem rendelkezik a magadott attribútummal, vagy az nem naplózandó.
public bool IsOriginalValueNull(string attributeName)
{
return (GetOriginalValue(attributeName) == null);
}
///
/// Megvizsgálja, hogy egy attribútum értéke változott-e, vagy sem.
///
/// Az attribútum neve
/// True, ha változott; egyébként false
public bool HasChanged(string attributeName)
{
return m_CurrentValues.ContainsKey(attributeName);
}
public IEnumerable ChangedAttributes()
{
string[] result = new string[m_CurrentValues.Count];
m_CurrentValues.Keys.CopyTo(result, 0);
return result;
}
#endregion
}
}