代码之家  ›  专栏  ›  技术社区  ›  scottm

如何将DBDataReader一般映射到castle.windsor解析的类型?

  •  0
  • scottm  · 技术社区  · 15 年前

    这让我困惑,所以这个问题可能会让人困惑。

    我有一个应用程序,它使用Ijob接口的实现来完成不同的任务。

    public interface IJob
    {
      int Id { get; set; }
      string Name { get; set; }
      void Run();
    }
    

    我正在使用castle.windsor.windsorcontainer来解决这些实现,并使用服务ID来帮助识别它们。

    WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    IJob jobToExecute = container.Resolve<IJob>("nameOfJob");
    

    我编写了一个小的通用扩展方法,只需将SQL列的值放入相应的属性中。

        public static void MapTo<T>(this DbDataReader reader, ref T instance) where T : class
        {
            Type objectType = typeof(T);
    
            foreach (PropertyInfo propertyInfo in objectType.GetProperties())
            {
                if (propertyInfo.CanWrite)
                {
                    int ordinal = -1;
                    try
                    {
                        ordinal = reader.GetOrdinal(propertyInfo.Name);
                        object value = reader[ordinal] == DBNull.Value ? null : reader[ordinal];
                        propertyInfo.SetValue(instance, value, null);
                    }
                    catch (IndexOutOfRangeException ex)
                    {
                        continue;
                    }
    
                }
            }
        }
    

    现在,因为不能实例化接口的实例,所以将ijob传递给这个方法是行不通的。但是,为了获得IOC容器的好处,我需要使用ijob接口在我的存储库中完成所有工作。因此,我用它来解析ijob实现,并将其传递给mapto方法来填充必要的属性:

        public IJob GetJobById(int id)
        {
            string cmdTxt = "SELECT Id, Name, Description, DateStarted, ScheduledCompletion, Completed FROM Jobs WHERE Id = @id";
    
            using (DbCommand cmd = _dataFactory.CreateCommand(cmdTxt))
            {
                _dataFactory.AddParam(cmd, "id", id, DbType.Int32);
                using (DbDataReader rdr = cmd.ExecuteReader())
                {
                    if (rdr.Read())
                    {
                        IJob job = _container.Resolve<IJob>("job.implementation");
                        rdr.MapTo<IJob>(ref job);
                        return job;
                    }
                    else
                    {
                        return null;
                    }
                }
            }
        }
    

    这是一个好的设计决定吗?你看到什么问题了吗?

    1 回复  |  直到 15 年前
        1
  •  1
  •   Mauricio Scheffer    15 年前

    嗯,首先,通过反射调用方法通常不好…看起来你在用温莎字典,而不是…

    我会写一个非通用的 MapTo (这需要 Type 作为参数)在已经存在的实例上操作(当使用 Activator.CreateInstance 您放弃了windsor解决的实例),然后从 ComponentCreatedEvent 事件在 IKernel . 像这样:

    container.Kernel.ComponentCreated += (model, instance) => {
      if (model.Service == typeof(IJob)) {
        // select id,name from jobs where id = model.Name
        // use MapTo to fill id,name into instance
      }
    }