using Ant.Core;
using Ant.Core.Visitors;
using Ant.Data;
using Ant.DbExpressions;
using Ant.Descriptors;
using Ant.Entity;
using Ant.Exceptions;
using Ant.Infrastructure;
using Ant.ORM;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
namespace Ant.Oracle
{
///
/// Oracle数据库
///
public class OracleContext : DbContext
{
DbContextServiceProvider _dbContextServiceProvider;
bool _convertToUppercase = true;
///
///
///
///
public OracleContext(string dbConnectionFactory)
{
Utils.CheckNull(dbConnectionFactory);
this._dbContextServiceProvider = new DbContextServiceProvider(ConvertToUppercase);
}
///
///
///
public bool ConvertToUppercase { get { return this._convertToUppercase; } set { this._convertToUppercase = value; } }
///
///
///
public override IDbContextServiceProvider DbContextServiceProvider
{
get { return this._dbContextServiceProvider; }
}
///
///
///
///
///
///
public override T Insert(T entity)
{
Utils.CheckNull(entity);
TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());
EnsureMappingTypeHasPrimaryKey(typeDescriptor);
MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
MemberInfo keyMember = typeDescriptor.PrimaryKey.MemberInfo;
object keyValue = null;
string sequenceName;
object sequenceValue = null;
MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);
if (defineSequenceMemberDescriptor != null)
{
sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);
}
Dictionary insertColumns = new Dictionary();
foreach (var kv in typeDescriptor.MappingMemberDescriptors)
{
MemberInfo member = kv.Key;
MappingMemberDescriptor memberDescriptor = kv.Value;
object val = null;
if (defineSequenceMemberDescriptor != null && memberDescriptor == defineSequenceMemberDescriptor)
{
val = sequenceValue;
}
else
val = memberDescriptor.GetValue(entity);
if (memberDescriptor == keyMemberDescriptor)
{
keyValue = val;
}
DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
insertColumns.Add(memberDescriptor, valExp);
}
if (keyValue == null)
{
throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
}
DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);
foreach (var kv in insertColumns)
{
e.InsertColumns.Add(kv.Key.Column, kv.Value);
}
this.ExecuteSqlCommand(e);
if (defineSequenceMemberDescriptor != null)
defineSequenceMemberDescriptor.SetValue(entity, sequenceValue);
return entity;
}
public override object Insert(Expression> body)
{
Utils.CheckNull(body);
TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(T));
EnsureMappingTypeHasPrimaryKey(typeDescriptor);
MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
string sequenceName;
object sequenceValue = null;
MappingMemberDescriptor defineSequenceMemberDescriptor = GetDefineSequenceMemberDescriptor(typeDescriptor, out sequenceName);
Dictionary insertColumns = InitMemberExtractor.Extract(body);
DbInsertExpression e = new DbInsertExpression(typeDescriptor.Table);
object keyVal = null;
foreach (var kv in insertColumns)
{
MemberInfo key = kv.Key;
MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);
if (memberDescriptor == null)
throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
if (memberDescriptor == defineSequenceMemberDescriptor)
throw new ChloeException(string.Format("Can not insert value into the column '{0}',because it's mapping member has define a sequence.", memberDescriptor.Column.Name));
if (memberDescriptor.IsPrimaryKey)
{
object val = ExpressionEvaluator.Evaluate(kv.Value);
if (val == null)
throw new ChloeException(string.Format("The primary key '{0}' could not be null.", memberDescriptor.MemberInfo.Name));
else
{
keyVal = val;
e.InsertColumns.Add(memberDescriptor.Column, DbExpression.Parameter(keyVal));
continue;
}
}
e.InsertColumns.Add(memberDescriptor.Column, typeDescriptor.Visitor.Visit(kv.Value));
}
if (keyMemberDescriptor == defineSequenceMemberDescriptor)
{
sequenceValue = ConvertIdentityType(this.GetSequenceNextValue(sequenceName), defineSequenceMemberDescriptor.MemberInfoType);
keyVal = sequenceValue;
e.InsertColumns.Add(keyMemberDescriptor.Column, DbExpression.Parameter(keyVal));
}
if (keyVal == null)
{
throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMemberDescriptor.MemberInfo.Name));
}
this.ExecuteSqlCommand(e);
return keyVal;
}
public override int Update(T entity)
{
Utils.CheckNull(entity);
TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(entity.GetType());
EnsureMappingTypeHasPrimaryKey(typeDescriptor);
MappingMemberDescriptor keyMemberDescriptor = typeDescriptor.PrimaryKey;
MemberInfo keyMember = keyMemberDescriptor.MemberInfo;
object keyVal = null;
IEntityState entityState = this.TryGetTrackedEntityState(entity);
Dictionary updateColumns = new Dictionary();
foreach (var kv in typeDescriptor.MappingMemberDescriptors)
{
MemberInfo member = kv.Key;
MappingMemberDescriptor memberDescriptor = kv.Value;
if (member == keyMember)
{
keyVal = memberDescriptor.GetValue(entity);
keyMemberDescriptor = memberDescriptor;
continue;
}
SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
if (attr != null)
continue;
object val = memberDescriptor.GetValue(entity);
if (entityState != null && !entityState.HasChanged(memberDescriptor, val))
continue;
DbExpression valExp = DbExpression.Parameter(val, memberDescriptor.MemberInfoType);
updateColumns.Add(memberDescriptor, valExp);
}
if (keyVal == null)
throw new ChloeException(string.Format("The primary key '{0}' could not be null.", keyMember.Name));
if (updateColumns.Count == 0)
return 0;
DbExpression left = new DbColumnAccessExpression(typeDescriptor.Table, keyMemberDescriptor.Column);
DbExpression right = DbExpression.Parameter(keyVal, keyMemberDescriptor.MemberInfoType);
DbExpression conditionExp = new DbEqualExpression(left, right);
DbUpdateExpression e = new DbUpdateExpression(typeDescriptor.Table, conditionExp);
foreach (var item in updateColumns)
{
e.UpdateColumns.Add(item.Key.Column, item.Value);
}
int ret = this.ExecuteSqlCommand(e);
if (entityState != null)
entityState.Refresh();
return ret;
}
public override int Update(Expression> body, Expression> condition)
{
Utils.CheckNull(body);
Utils.CheckNull(condition);
TypeDescriptor typeDescriptor = TypeDescriptor.GetDescriptor(typeof(T));
Dictionary updateColumns = InitMemberExtractor.Extract(body);
DbExpression conditionExp = typeDescriptor.Visitor.VisitFilterPredicate(condition);
DbUpdateExpression e = new DbUpdateExpression(typeDescriptor.Table, conditionExp);
foreach (var kv in updateColumns)
{
MemberInfo key = kv.Key;
MappingMemberDescriptor memberDescriptor = typeDescriptor.TryGetMappingMemberDescriptor(key);
if (memberDescriptor == null)
throw new ChloeException(string.Format("The member '{0}' does not map any column.", key.Name));
if (memberDescriptor.IsPrimaryKey)
throw new ChloeException(string.Format("Could not update the primary key '{0}'.", memberDescriptor.Column.Name));
SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
if (attr != null)
throw new ChloeException(string.Format("Could not update the column '{0}',because it's mapping member has define a sequence.", memberDescriptor.Column.Name));
e.UpdateColumns.Add(memberDescriptor.Column, typeDescriptor.Visitor.Visit(kv.Value));
}
if (e.UpdateColumns.Count == 0)
return 0;
return this.ExecuteSqlCommand(e);
}
int ExecuteSqlCommand(DbExpression e)
{
IDbExpressionTranslator translator = this.DbContextServiceProvider.CreateDbExpressionTranslator();
List parameters;
string cmdText = translator.Translate(e, out parameters);
int r = this.db.ExecuteNonQuery(cmdText, parameters.ToArray());
return r;
}
object GetSequenceNextValue(string sequenceName)
{
if (this.ConvertToUppercase)
sequenceName = sequenceName.ToUpper();
object ret = this.db.ExecuteScalar(string.Concat("SELECT \"", sequenceName, "\".\"NEXTVAL\" FROM \"DUAL\""));
if (ret == null || ret == DBNull.Value)
{
throw new ChloeException(string.Format("Unable to get the sequence '{0}' next value.", sequenceName));
}
return ret;
}
///
///
///
///
///
///
static MappingMemberDescriptor GetDefineSequenceMemberDescriptor(TypeDescriptor typeDescriptor, out string sequenceName)
{
sequenceName = null;
MappingMemberDescriptor defineSequenceMemberDescriptor = null;
foreach (MappingMemberDescriptor memberDescriptor in typeDescriptor.MappingMemberDescriptors.Values)
{
SequenceAttribute attr = (SequenceAttribute)memberDescriptor.GetCustomAttribute(typeof(SequenceAttribute));
if (attr != null)
{
if (defineSequenceMemberDescriptor != null)
{
throw new ChloeException(string.Format("映射类型'{0}'不能确定身份的多个成员。", typeDescriptor.EntityType.FullName));
//throw new ChloeException(string.Format("Mapping type '{0}' can not define multiple identity members.", typeDescriptor.EntityType.FullName));
}
if (string.IsNullOrEmpty(attr.Name))
{
throw new ChloeException("序列名称不能为空。");
//throw new ChloeException("Sequence name can not be empty.");
}
sequenceName = attr.Name;
defineSequenceMemberDescriptor = memberDescriptor;
}
}
if (defineSequenceMemberDescriptor != null)
EnsureDefineSequenceMemberType(defineSequenceMemberDescriptor);
return defineSequenceMemberDescriptor;
}
static void EnsureDefineSequenceMemberType(MappingMemberDescriptor defineSequenceMemberDescriptor)
{
if (defineSequenceMemberDescriptor.MemberInfoType != UtilConstants.TypeOfInt16 && defineSequenceMemberDescriptor.MemberInfoType != UtilConstants.TypeOfInt32 && defineSequenceMemberDescriptor.MemberInfoType != UtilConstants.TypeOfInt64)
{
throw new ChloeException("Identity type must be Int16,Int32 or Int64.");
}
}
static void EnsureMappingTypeHasPrimaryKey(TypeDescriptor typeDescriptor)
{
if (!typeDescriptor.HasPrimaryKey())
throw new ChloeException(string.Format("Mapping type '{0}' does not define a primary key.", typeDescriptor.EntityType.FullName));
}
static object ConvertIdentityType(object identity, Type conversionType)
{
if (identity.GetType() != conversionType)
return Convert.ChangeType(identity, conversionType);
return identity;
}
}
}