如何在不引起循环引用的情况下对WCF使用延迟加载?

时间:2011-03-21 19:50:58

标签: c# wcf architecture mvvm lazy-loading

我正在使用Model类上的DataAnnotation属性进行验证,而Model类用于在应用程序的客户端和服务器端进行验证。

我的问题是,我无法弄清楚如何在不导致循环引用的情况下延迟加载我的模型属性

涉及的图书馆是:

  • WCF服务库
  • 客户端DataAccess Library
  • 模型库

由于模型库在客户端和服务器端都用于数据验证,因此我无法从模型库中引用DataAccess库。因此,我该如何设置延迟加载?

例如,我有一个ConsumerModel,它具有PhoneNumbers属性,应该延迟加载。如何在不参考客户端DAL的情况下从ConsumerModel中加载PhoneNumberModel?

客户端DAL:

using MyModels;

public class ConsumerDataAccess
{
    public ConsumerModel GetConsumerById(int id)
    {
        ConsumerDTO dto = WCFService.GetConsumer(id);
        return new ConsumerModel(dto);
    }
}

ConsumerModel:

public class ConsumerModel
{
    public ObservableCollection<PhoneNumberModel> _phoneNumbers;

    public ObservableCollection<PhoneNumberModel> PhoneNumbers
    {
        get
        {
            if (_phoneNumbers == null)
            {
                // Can't reference DataAccess Library since that would cause a Circular Reference
            }
        }
    }
}

我可以采用哪些替代方法来使这种架构发挥作用?

我更希望对模型进行验证,并使用客户端和服务器端的模型进行验证。我还希望继续使用DataAnnotation进行验证。

修改

如果有人对此感兴趣,这是基于Lawrence Wenham答案的最终解决方案。我最终使用了代表而不是事件。

DAL:

public class ConsumerDataAccess
{
    public ConsumerModel GetConsumerById(int id)
    {
        ConsumerDTO dto = WCFService.GetConsumer(id);
        ConsumerModel rtnValue = new ConsumerModel(dto);
        ConsumerModel.LazyLoadData = LazyLoadConsumerData;
        return rtnValue;
    }
}

private object LazyLoadConsumerData(string key, object args)
{
    switch (key)
    {
        case "Phones":
            return PhoneDataAccess.GetByConsumerId((int)args);
        default:
            return null;
    }
}

模型库:

public class ConsumerModel
{
    public delegate object LazyLoadDataDelegate(string id, object args);
    public LazyLoadDataDelegate LazyLoadData { get; set; }

    public ObservableCollection<PhoneNumberModel> _phoneNumbers;

    public ObservableCollection<PhoneNumberModel> PhoneNumbers
    {
        get
        {
            if (_phoneNumbers == null && LazyLoadData != null)
            {
                _phoneNumbers = (ObservableCollection<PhoneNumberModel>)
                        LazyLoadData("Phones", ConsumerId);
            }
            return _phoneNumbers;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

一种方法可能是在Model类属性的get {}中引发事件,然后在客户端实现一个延迟加载管理器,该管理器具有对DAL的引用。 EG:

public class LazyLoadEventArgs: EventArgs
{
    public object Data { get; set; }

    public string PropertyName { get; set; }

    public int Key { get; set; }
}

然后在你的Model类中:

public event EventHandler<LazyLoadEventArgs> LazyLoadData;

public ObservableCollection<PhoneNumberModel> PhoneNumbers
{
    get
    {
        if (_phoneNumbers == null)
        {
            LazyLoadEventArgs args = new LazyLoadEventArgs {
                PropertyName = "PhoneNumbers",
                Key = this.Id
            };
            LazyLoadData(this, args);
            if (args.Data != null)
               this._phoneNumbers = args.Data as ObservableCollection<PhoneNumberModel>;
        }
        return _phoneNumbers;
    }
}

LazyLoadData事件的处理程序将从客户端的DAL获取数据,然后将其存储在LazyLoadEventArgs的.Data属性中。 EG:

private void Model_HandleLazyLoadData(object sender, LazyLoadEventArgs e)
{
    switch (e.PropertyName)
    {
        case "PhoneNumbers":
            e.Data = DAL.LoadPhoneNumbers(e.Key);
            break;
        ...
    }
}

答案 1 :(得分:0)

不要对WCF使用“延迟加载”。网络通信耗时。如果您打算使用PhoneNumbers,您的服务应公开将返回Customer电话号码的方法。其他方法是使用WCF Data Services,它为客户端linq查询提供了通过Expand方法定义预先加载的能力。

您应该将服务呼叫减少到最低限度。

再次阅读你的问题后,我不明白你为什么要在服务和客户之间分享模型。模型是严格的客户特征。唯一的共享部分应该是DTO。