3

我正在尝试在 Windows Phone 库中实现 Windows Azure 移动服务。我是这样DataContract定义的:

[Table]
[DataContract]
public class ToDoCategory : NotifyBase, ISyncableBase
{
    [IgnoreDataMember]
    [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
    public int LocalId { get; set; }

    [Column(CanBeNull = true)]
    [DataMember(Name="id")]
    public int RemoteId { get; set; }

    [Column]
    [DataMember]
    public bool IsDeleted { get; set; }

    [Column]
    [DataMember]
    public DateTime RemoteLastUpdated { get; set; }

    [Column(CanBeNull = true)]
    [DataMember]
    public DateTime? LocalLastUpdated { get; set; }
}

然后我尝试使用 LINQ 表达式从表中加载数据,如下所示(删除了不必要的细节):

public async void SynchronizeAsync<TEntity>() where TEntity : ISyncableBase
{           
    var remoteTable = MobileServiceConnection.GetTable<TEntity>();

    //Get new entities
    var newEntities = await remoteTable.Where(item => item.RemoteLastUpdated > currentTimeStamp).ToListAsync();
}

但是,一旦我来到最后一行,我就会收到错误消息说"The member 'RemoteLastUpdated' is not supported in the 'Where' Mobile Services query expression 'Convert(item).RemoteLastUpdated'." Same is the case for IsDeletedand even RemoteId。显然,我只是不能使用Where运算符。有什么我想念的吗?

编辑:这种解决了我的问题,我不明白为什么!解释会很有帮助。我将通用方法更改为以下内容:

public async void SynchronizeAsync<TEntity>() where TEntity : class, ISyncableBase, new()

请注意,我添加了约束classnew泛型TEntity,现在它工作正常。知道这是怎么发生的吗?

4

3 回答 3

2

我看到您可以通过使用classandnew()约束来解锁自己。你实际上只需要第一个 - 这应该工作:

public async Task SynchronizeAsync<TEntity>()
    where TEntity : class, ISyncableBase { ... }

现在,为什么一个有效而另一个无效,为这两种情况生成的表达式是不同的。有了class约束,这是为您的 Where 子句生成的表达式:

item => (item.RemoteLastUpdated > currentTimeStamp)

而如果你没有那个约束,这是创建的表达式:

item => (Convert(item).RemoteLastUpdated > currentTimeStamp)

这是因为一个被约束为接口类型的泛型对象可能是一个值类型,并且它需要被装箱为一个对象,以便我们可以访问它的属性。Azure 移动服务客户端 SDK 使用的 Linq-to-OData 转换器通常不支持转换。

下面的代码显示了表达式的两个版本,并且具有仅适用于class约束的通用方法的版本。

public sealed partial class MainPage : Page
{
    public static MobileServiceClient MobileService = new MobileServiceClient("appUrl", "appKey");

    public MainPage()
    {
        this.InitializeComponent();
    }

    private async void btnStart_Click(object sender, RoutedEventArgs e)
    {
        AddToDebug("No class constraint:");
        NoClassConstraint<ToDoCategory>();
        AddToDebug("With class constraint:");
        WithClassConstraint<ToDoCategory>();

        //await SynchronizeAsync<ToDoCategory>();
    }

    private void NoClassConstraint<TEntity>() where TEntity : ISyncableBase
    {
        DumpWhereExpression<TEntity>(item => item.RemoteLastUpdated > DateTime.Now);
    }

    private void WithClassConstraint<TEntity>() where TEntity : class, ISyncableBase
    {
        DumpWhereExpression<TEntity>(item => item.RemoteLastUpdated > DateTime.Now);
    }

    public async Task SynchronizeAsync<TEntity>() where TEntity : class, ISyncableBase
    {
        try
        {
            var remoteTable = MobileService.GetTable<TEntity>();

            DateTime currentTimeStamp = DateTime.UtcNow.Date;
            //Get new entities
            var newEntities = await remoteTable.Where(item => ((ISyncableBase)item).RemoteLastUpdated > currentTimeStamp).ToListAsync();
            AddToDebug("New entities: {0}", string.Join(" - ", newEntities.Select(e => e.RemoteLastUpdated)));
        }
        catch (Exception ex)
        {
            AddToDebug("Error: {0}", ex);
        }
    }

    private void DumpWhereExpression<T>(Expression<Func<T, bool>> predicate)
    {
        AddToDebug("Predicate: {0}", predicate);
    }

    void AddToDebug(string text, params object[] args)
    {
        if (args != null && args.Length > 0) text = string.Format(text, args);
        this.txtDebug.Text = this.txtDebug.Text + text + Environment.NewLine;
    }
}

public interface ISyncableBase
{
    DateTime RemoteLastUpdated { get; set; }
}
[DataContract]
public class NotifyBase { }
public class TableAttribute : Attribute { }
public class ColumnAttribute : Attribute
{
    public string DbType { get; set; }
    public bool IsDbGenerated { get; set; }
    public bool IsPrimaryKey { get; set; }
    public bool CanBeNull { get; set; }
}
[Table]
[DataContract]
public class ToDoCategory : NotifyBase, ISyncableBase
{
    [IgnoreDataMember]
    [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
    public int LocalId { get; set; }

    [Column(CanBeNull = true)]
    [DataMember(Name = "id")]
    public int RemoteId { get; set; }

    [Column]
    [DataMember]
    public bool IsDeleted { get; set; }

    [Column]
    [DataMember]
    public DateTime RemoteLastUpdated { get; set; }

    [Column(CanBeNull = true)]
    [DataMember]
    public DateTime? LocalLastUpdated { get; set; }
}
于 2013-10-10T04:09:20.887 回答
1

您的 RemoteLastUpdated 列是否存在于您的 TEntity 类中?

尝试这个:

public async void SynchronizeAsync<ToDoCategory>()
{           
    var remoteTable = MobileServiceConnection.GetTable<ToDoCategory>();

    //Get new entities
    var newEntities = await remoteTable.Where(item => item.RemoteLastUpdated > currentTimeStamp).ToListAsync();
}

如果上面的代码有效,您应该将“RemoteLastUpdated”移动到从 ISyncableBase 继承的类中,并将此列放在那里。之后,将您的 ToDoCategory 类更改为从这个新类继承。

样本:

    [DataContract]
    public class MobEntity : NotifyBase
    {
        [Column]
        [DataMember]
        public DateTime RemoteLastUpdated { get; set; }
    }

[Table]
[DataContract]
public class ToDoCategory : MobEntity , ISyncableBase
{
    [IgnoreDataMember]
    [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
    public int LocalId { get; set; }

    [Column(CanBeNull = true)]
    [DataMember(Name="id")]
    public int RemoteId { get; set; }

    [Column]
    [DataMember]
    public bool IsDeleted { get; set; }

    [Column]
    [DataMember]
    public DateTime RemoteLastUpdated { get; set; }

    [Column(CanBeNull = true)]
    [DataMember]
    public DateTime? LocalLastUpdated { get; set; }
}

最后:

   public async void SynchronizeAsync<MobEntity>() where MobEntity : ISyncableBase
    {           
        var remoteTable = MobileServiceConnection.GetTable<ToDoCategory>();

        //Get new entities
        var newEntities = await remoteTable.Where(item => item.RemoteLastUpdated > currentTimeStamp).ToListAsync();
    }
于 2013-10-09T11:38:55.860 回答
0

首先:在这种情况下,您不需要使用泛型。

其次,Where 子句有效,因为您使用了正确的表名。

var table = App.MobileService.GetTable<GameScore>();
var resultList = await table.Where(g => g.Score > 500).ToListAsync();
于 2013-10-09T13:51:16.953 回答