我使用 Subsonic 生成了一个不错的 DAL。有没有办法可以为 BLL 生成骨架?我不想将 SS 层直接插入我的 GUI。
我已经在两个 SS 论坛中跋涉,似乎每个人都将SSS 生成的层称为 DAL,但他们将其用作 BLL。
您是否使用过 SS 并将 DAL 和 BLL 层分开,而无需从头开始手动编码 BLL?
我使用 Subsonic 生成了一个不错的 DAL。有没有办法可以为 BLL 生成骨架?我不想将 SS 层直接插入我的 GUI。
我已经在两个 SS 论坛中跋涉,似乎每个人都将SSS 生成的层称为 DAL,但他们将其用作 BLL。
您是否使用过 SS 并将 DAL 和 BLL 层分开,而无需从头开始手动编码 BLL?
是的,我使用单独的 DAL 和 BLL,除非项目非常小并且业务逻辑不多。
你是对的,在 BAL 中为 DAL 属性执行所有实现真的很烦人,并且破坏了 SS 的代码生成优势。我创建了一个小控制台应用程序,它通过 DAL 并生成骨架 BLL:
这是它的代码。请记住这是非常粗略的(我把它贴在这里希望得到 SO 研究员的审查并改进它):
class Program
{
static void Main(string[] args)
{
InitTypesDictionary();
ProcessFile("c:\\temp\\myBll", "YOUR_BLL_NAMESPACE");//args[0], args[1]);
Console.ReadLine();
}
private static void InitTypesDictionary()
{
typesMap = new Dictionary<string, string>();
typesMap.Add("System.String", "string");
typesMap.Add("System.Int32", "int");
typesMap.Add("System.Decimal", "decimal");
typesMap.Add("System.Double", "double");
typesMap.Add("System.Guid", "Guid");
typesMap.Add("System.DateTime", "DateTime");
typesMap.Add("System.Boolean", "bool");
typesMap.Add("System.Byte", "byte");
typesMap.Add("System.Short", "short");
typesMap.Add("System.Nullable`1[System.Int32]", "int?");
typesMap.Add("System.Nullable`1[System.DateTime]", "DateTime?");
typesMap.Add("System.Nullable`1[System.Decimal]", "decimal?");
typesMap.Add("System.Nullable`1[System.Double]", "double?");
typesMap.Add("System.Nullable`1[System.Boolean]", "bool?");
}
private static void WriteError(string msg)
{
WriteInfo(msg, ConsoleColor.Red);
}
private static void WriteTypeName(string name)
{
WriteInfo(name, ConsoleColor.Blue);
}
private static void WriteInfo(string info, ConsoleColor cc)
{
ConsoleColor clr = Console.ForegroundColor;
Console.ForegroundColor = cc;
Console.WriteLine(info);
Console.ForegroundColor = clr;
}
private static void ProcessFile(string savePath, string _namespace)
{
Assembly asm = Assembly.GetAssembly(typeof(ROMS.DAL.RomsAdBusiness));
//Assembly asm = Assembly.ReflectionOnlyLoad("ROMS.DAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
Type[] types = asm.GetTypes();
foreach (Type t in types)
{
if (t.BaseType.Name.Contains("ActiveRecord"))
{
WriteTypeName("Processing " + t.Name);
ProcessType(t, savePath, _namespace);
}
}
}
private static void ProcessType(Type t, string path, string nsp)
{
string className = t.Name.Substring(4);
StringBuilder sbCode = new StringBuilder();
sbCode.Append(imports);
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(comments, t.Name, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"));
sbCode.AppendFormat(namespaceStart, nsp);
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(_class, className);
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(dalObject, t.Name);
sbCode.AppendFormat(regionStart, "ctor");
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(ctorString, className, t.Name);
sbCode.AppendFormat(ctorStringPK, className, t.Name);
sbCode.AppendFormat(ctorStringObject, className, t.Name);
sbCode.AppendFormat(regionEnd, "");
//sbCode.Append(Environment.NewLine);
PropertyInfo[] properties = t.GetProperties();
//if (properties.Count() > 0)
//{
sbCode.AppendFormat(regionStart, "Properties");
//sbCode.Append(Environment.NewLine);
//}
foreach (PropertyInfo p in properties)
{
if (SkipProperties.Contains(p.Name)) continue;
if (p.Name == className)
sbCode.AppendFormat(propertyValue, GetPropertyTypeName(p.PropertyType.ToString()), p.Name + "Value", p.Name);
else if (p.Name.ToLower().Contains("roms"))
sbCode.AppendFormat(propertyInternal, GetPropertyTypeName(p.PropertyType.ToString()), p.Name);
else
sbCode.AppendFormat(property, GetPropertyTypeName(p.PropertyType.ToString()), p.Name);
//sbCode.Append(Environment.NewLine);
}
sbCode.Append(isNew_Validate_Properties);
//if (properties.Count() > 0)
//{
sbCode.AppendFormat(regionEnd, "");
//sbCode.Append(Environment.NewLine);
//}
sbCode.AppendFormat(regionStart, "methods");
sbCode.Append(saveMethod);
sbCode.Append(deleteMethod.Replace("_CLASSNAME_", className));
sbCode.AppendFormat(regionEnd, "");
//Add Fetch as Collection Methods
sbCode.Append(getCollectionsMethods.Replace("_CLASSNAME_", className).Replace("_DOUBLEQUOTE_", "\""));
//Define Columns Structure
Type cols = t.GetNestedType("Columns");
if (cols != null)
{
StringBuilder sbCols = new StringBuilder(columnsStructStart);
MemberInfo[] fields = cols.GetMembers();
foreach (MemberInfo mi in fields)
{
if (mi.MemberType == MemberTypes.Field)
sbCols.AppendFormat(columnDeclaration, mi.Name);
}
sbCols.Append(columnsStructEnd);
sbCode.Append(sbCols.ToString());
}
sbCode.Append("}_NL_}_NL_");
var fileName = WriteFile(path, nsp, className, sbCode);
WriteInfo("Written file: " + fileName, ConsoleColor.Yellow);
}
private static string GetPropertyTypeName(string s)
{
if (typesMap.ContainsKey(s)) return typesMap[s];
if (s.Contains("Nullable`"))
{
s = s.Substring(s.IndexOf("[") + 1);
s = s.Substring(0, s.IndexOf("]"));
if (typesMap.ContainsKey(s))
return typesMap[s] + "?";
else
return "Nullable<" + s + ">";
}
if (s.StartsWith("System."))
return s.Substring(7);
if (s.LastIndexOf(".") > 0)
return s.Substring(s.LastIndexOf(".") + 1);
return s;
}
private static string WriteFile(string path, string nsp, string typeName, StringBuilder sbCode)
{
string filename = GetFilePath(path, nsp, typeName);
TextWriter tw = new StreamWriter(filename);
StringBuilder sb = sbCode.Replace("_BS_", "{")
.Replace("_BE_", "}")
.Replace("_NL_", Environment.NewLine)
.Replace("_DOUBLEQUOTE_", "\"");
tw.Write(sb.ToString());
tw.Flush();
tw.Close();
return filename;
}
private static string GetFilePath(string path, string nsp, string typeName)
{
path = path.EndsWith("\\") ? path : path + "\\";
path += typeName + ".cs";
return path;
}
static bool IsNullableType(Type theType)
{
return (theType.IsGenericType && theType.
GetGenericTypeDefinition().Equals
(typeof(Nullable<>)));
}
private static string[] SkipProperties = new[]{"IsLoaded", "IsNew", "IsDirty",
"TableName", "ProviderName",
"NullExceptionMessage","InvalidTypeExceptionMessage",
"LengthExceptionMessage",
"AuditId","Schema","ValidateWhenSaving","DirtyColumns","Errors"};
static IDictionary<string, string> typesMap;
static string comments = @"_NL_///<sumary>
///This class uses {0} from YOUR_DAL_NAMESPACE
///Created by MyCodeGen (YOUR_NAME) on {1}
///</sumary>_NL_";
static string dalObject = "_NL_private YOUR_DAL_NAMESPACE.{0} _dalObject;_NL_";
static string namespaceStart = "namespace {0} _NL_ _BS_ _NL_";
static string property = "public {0} {1} _NL_ _BS_ _NL_ get _BS_ return
_dalObject.{1}; _BE_ _NL_ " +
"set _BS_ _dalObject.{1} = value; _BE_ _NL_ _BE_ _NL_";
static string propertyInternal = "internal {0} {1} _NL_ _BS_ _NL_ get _BS_ return
_dalObject.{1}; _BE_ _NL_ " +
"set _BS_ _dalObject.{1} = value; _BE_ _NL_ _BE_ _NL_";
static string propertyValue = "public {0} {1} _NL_ _BS_ _NL_ get _BS_ return
_dalObject.{2}; _BE_ _NL_ " +
"set _BS_ _dalObject.{2} = value; _BE_ _NL_ _BE_ _NL_";
static string _class = "public partial class {0} _NL_ _BS_ ";
static string regionStart = "#region {0} _NL_";
static string regionEnd = "#endregion{0}_NL__NL_";
static string ctorString = "[DebuggerStepThrough]_NL_public {0}() _NL_
_BS__NL__dalObject = new YOUR_DAL_NAMESPACE.{1}(); _NL_ _BE_ _NL_";
static string ctorStringPK = "[DebuggerStepThrough]_NL_public {0}(int pk) _NL_
_BS__NL__dalObject = new YOUR_DAL_NAMESPACE.{1}(pk);_NL__BE__NL_";
static string ctorStringObject = "[DebuggerStepThrough]_NL_public
{0}(YOUR_DAL_NAMESPACE.{1} dalObject) _NL_ _BS__NL__dalObject = dalObject; _NL_
if(_dalObject==null) _NL__dalObject = new YOUR_DAL_NAMESPACE.{1}();_BE_ _NL_";
static string columnsStructStart = @"_NL_#region Columns Struct
public struct Columns
{
";
static string columnsStructEnd=@"
}
#endregion_NL_";
static string columnDeclaration = "public static string
{0}=_DOUBLEQUOTE_{0}_DOUBLEQUOTE_;_NL_";
static string saveMethod = "_NL_public bool Save() _NL__BS__NL_bool ret=IsValid;
_NL_ if(ret)_NL__dalObject.Save(); _NL_ return ret;_NL__BE__NL_";
static string deleteMethod = @"public int Delete()
{
string pkColumn=_dalObject.GetSchema().PrimaryKey.ColumnName;
object pkValue = _dalObject.GetColumnValue(pkColumn);
return ActiveRecord<Roms_CLASSNAME_>.Delete(pkValue);
}
";
static string isNew_Validate_Properties = @"/// <summary>
/// Enquiries underlying database object to know if it is persisted in
///database or not.
/// True if object has never been saved to database, false otherwise
/// </summary>
public bool IsNew
_BS_
get _BS_ return _dalObject.IsNew; _BE_
_BE_
/// <summary>
/// Validates the underlying dataobject for the lengeth, range of the
///columns defined
/// in database. Should be called before pushing object to database
///(before saving or updating).
/// </summary>
public bool IsValid
_BS_
get _BS_ return _dalObject.Validate(); _BE_
_BE_
/// <summary>
/// This string of validation error messages (<br/> seperated)
/// if the object is not valid.
/// </summary>
/// <returns>string</returns>
public string GetErrors
_BS_
get
_BS_
StringBuilder sb=new StringBuilder();
foreach (var v in _dalObject.GetErrors())
sb.AppendFormat(_DOUBLEQUOTE__BS_0_BE_<br/>_DOUBLEQUOTE_, v);
return sb.ToString();
_BE_
_BE__NL_";
static string imports =
@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Diagnostics;
using System.Reflection;
using SubSonic;
using YOUR_DAL_NAMESPACE;
";
static string getCollectionsMethods = @"#region Fetch as Collection Methods
///<sumary>
///Returns the collection containing objects of type _CLASSNAME_ corresponding to
_CLASSNAME_Collection
///objects passed
///</sumary>
[DebuggerStepThrough]
public static IList<_CLASSNAME_> _CLASSNAME_s(Roms_CLASSNAME_Collection coll)
{
IList<_CLASSNAME_> list=new List<_CLASSNAME_>();
foreach(var roprof in coll)
list.Add(new _CLASSNAME_(roprof));
return list;
}
/// <summary>
/// Returns the IList<_CLASSNAME_> of _CLASSNAME_ objects
/// </summary>
/// <returns>IList<_CLASSNAME_></returns>
[DebuggerStepThrough]
public static IList<_CLASSNAME_> _CLASSNAME_s()
{
return _CLASSNAME_s(_DOUBLEQUOTE__DOUBLEQUOTE_,null);
}
/// <summary>
/// Returns the IList<_CLASSNAME_> of _CLASSNAME_ objects having
/// value of <see cref=_DOUBLEQUOTE_columnName_DOUBLEQUOTE_/> =
///<see cref=_DOUBLEQUOTE_value_DOUBLEQUOTE_/>
/// </summary>
/// <param name=_DOUBLEQUOTE_columnName_DOUBLEQUOTE_>Name of the column</param>
/// <param name=_DOUBLEQUOTE_value_DOUBLEQUOTE_>Value of the column</param>
/// <returns>IList<_CLASSNAME_></returns>
[DebuggerStepThrough]
public static IList<_CLASSNAME_> _CLASSNAME_s(string columnName, object value)
{
IList<_CLASSNAME_> collection = new List<_CLASSNAME_>();
Roms_CLASSNAME_Collection coll = null;
if (!string.IsNullOrEmpty(columnName))
{
Roms_CLASSNAME_ obj = new Roms_CLASSNAME_();
columnName = obj.GetType().GetNestedType(
_DOUBLEQUOTE_Columns_DOUBLEQUOTE_).
GetField(columnName).GetValue(obj).ToString();
}
if (!string.IsNullOrEmpty(columnName) && value != null)
{
coll = (new Roms_CLASSNAME_Collection()).Where(columnName,
value).Load();
}
else
{
coll = (new Roms_CLASSNAME_Collection()).Load();
}
if (coll != null)
foreach (var v in coll)
collection.Add(new _CLASSNAME_(v));
return collection;
}
#endregion
";
PS:- 如果您尝试过,请注意 YOUR_DAL_NAMESPACE、YOUR_BLL_NAMESPACE 和 YOUR_NAME 占位符。
不,但有一些选择。您可以使用部分类文件扩展生成的表类以添加更多逻辑,这对于许多较小的应用程序可能已经足够了。您可能还需要 DTO 类,并且 subsonic 3 的表类通常似乎作为 DTO 对象工作。您可以在 subsonic 3 中编写额外的 t4 模板文件来创建业务类,每个表一个类。代码将很像现有的模板代码,所以应该很容易。您甚至可以在 ss3 中获取表类的模板代码,并在 ss2 中使用它们来生成文件。这取决于您想要生成一组简单的 BLL 类的程度。