【问题标题】:Updating a document in Firebase Firestore from .Net Core console app从 .Net Core 控制台应用程序更新 Firebase Firestore 中的文档
【发布时间】:2020-01-17 20:56:28
【问题描述】:

用例

使用 firestore 作为持久性形式的 Angular Firebase 应用程序需要与 Discord Bot 通信。我已经构建了一个同步器机器人来在现有的外部机器人和 Web 应用程序之间进行调解。 有足够的信息可以找到文档并进行更新。

问题

由于转换问题,无法更新。
例外:Unable to create converter for type Models.Participant

问题

在尝试了几种解决方案(主要使用 json 转换)后,我简化了代码以便更好地掌握情况。我假设缺少一些明显的东西,但由于我对 firebase (firestore) 缺乏经验,我目前无法看到什么。

public async Task<bool> NextTurn(string encounterName)
{
    var encounterSnapshotQuery = await _encountersCollection.WhereEqualTo("name", encounterName).GetSnapshotAsync();

    foreach (DocumentSnapshot encounterSnapshot in encounterSnapshotQuery.Documents)
    {
        Dictionary<string, object> data = encounterSnapshot.ToDictionary();
        var name = data["name"].ToString();

        if (name == encounterName)
        {
            var participants = data["participants"].ToParticipants();
            var orderedParticipants = participants.OrderByDescending(x => x.initiative + x.roll).ToList();

            var current = orderedParticipants.Single(x => x.isCurrent != null && x.isCurrent is bool && (bool)x.isCurrent);
            var currentIndex = orderedParticipants.FindIndex(x => x.characterName == current.characterName);
            var next = orderedParticipants[currentIndex + 1];

            current.hasPlayedThisTurn = true;
            current.isCurrent = false;
            next.isCurrent = true;

            var updates = new Dictionary<FieldPath, object>
            {
                { new FieldPath("participants"),  orderedParticipants }
            };

            try
            {
                await encounterSnapshot.Reference.UpdateAsync(updates);
            }
            catch (Exception ex)
            {
                _logger.LogError(new EventId(), ex, "Update failed.");
            }
        }

    }

    return true;
}

如果方法有明显错误,也欢迎提出建议。

更新

完整的异常消息:

 at Google.Cloud.Firestore.Converters.ConverterCache.CreateConverter(Type targetType)
   at Google.Cloud.Firestore.Converters.ConverterCache.<>c.<GetConverter>b__1_0(Type t)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Google.Cloud.Firestore.Converters.ConverterCache.GetConverter(Type targetType)
   at Google.Cloud.Firestore.SerializationContext.GetConverter(Type targetType)
   at Google.Cloud.Firestore.ValueSerializer.Serialize(SerializationContext context, Object value)
   at Google.Cloud.Firestore.Converters.ListConverterBase.Serialize(SerializationContext context, Object value)
   at Google.Cloud.Firestore.ValueSerializer.Serialize(SerializationContext context, Object value)
   at Google.Cloud.Firestore.WriteBatch.<>c__DisplayClass12_0.<Update>b__1(KeyValuePair`2 pair)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
   at Google.Cloud.Firestore.WriteBatch.Update(DocumentReference documentReference, IDictionary`2 updates, Precondition precondition)
   at Google.Cloud.Firestore.DocumentReference.UpdateAsync(IDictionary`2 updates, Precondition precondition, CancellationToken cancellationToken)

参与者模型

public class Participant
{
    public string playerName { get; set; }
    public int experience { get; set; }
    public int level { get; set; }
    public string characterName { get; set; }
    public string playerUid { get; set; }
    public object joined { get; set; }
    public string type { get; set; }
    public object abilities { get; set; }
    public int roll { get; set; }
    public bool? isCurrent { get; set; }
    public int sizeModifier { get; set; }
    public int initiative { get; set; }
    public bool? hasPlayedThisTurn { get; set; }
    public string portraitUrl { get; set; }
}

用于在 Firestore 上创建模型的参与者打字稿界面

export interface Participant {
    playerName: string,
    characterName: string,
    initiative: number,
    roll: number,
    playerUid: string,
    joined: Date,
    portraitUrl: string,
    level: number,
    experience: number,
    isCurrent: boolean,
    sizeModifier: number,
    type: string,
    abilities: {
        strength: number,
        dexterity: number,
        constitution: number,
        intelligence: number,
        wisdom: number,
        charisma: number
    },
    hasPlayedThisTurn: boolean
}

请注意,我曾尝试更改 C# 模型以尝试解决此问题。这是当前的状态。不管我做了什么改变,消息都是一样的。

【问题讨论】:

  • 在c#中,firestore自动序列化的类型需要firestore可以转换。如果我没记错的话,该错误应该还有更多内容,例如是什么导致转换器在错误调用堆栈中可能失败?这里的大部分代码都无关紧要,因为它只与 Participants 类的定义有关。此行是否出现错误:await encounterSnapshot.Reference.UpdateAsync(updates);?你能提供 Models.Participant 的定义吗?
  • 是的,这就是错误发生的地方,其余的我已经更新了问题。
  • 很酷,谢谢,我去看看

标签: c# firebase .net-core google-cloud-firestore


【解决方案1】:

这里有两种解决方案:

  1. 你需要用
  2. 装饰类
[FirestoreData]
public class Participant
{
    [FirestoreProperty]
    public string playerName { get; set; }

    [FirestoreProperty("playerExperience")] //you can give the properties custom names as well
    public int experience { get; set; }
 
    //so on
    public int level { get; set; }
    public string characterName { get; set; }
    public string playerUid { get; set; }
    public object joined { get; set; }
    public string type { get; set; }
    public object abilities { get; set; }
    public int roll { get; set; }
    public bool? isCurrent { get; set; }
    public int sizeModifier { get; set; }
    public int initiative { get; set; }
    public bool? hasPlayedThisTurn { get; set; }
    public string portraitUrl { get; set; }
}

通过将参与者转换为 ExpandoObject ExpandoObject Reference

建议在不使用 Newtonsoft.Json 的情况下转换对象: How do you convert any C# object to an ExpandoObject?

但是使用 Newtonsoft.Json 很容易理解,这就是我所做的:

var serializedParticipant = JsonConvert.SerializeObject(participant);
var deserializedParticipant = JsonConvert.DeserializeObject<ExpandoObject>(serializedParticipant);

//setting the document
await documentReference.UpdateAsync(deserializedParticipant);

然后将您的参与者更新为 ExpandoObject 而不是 Model.Participant

【讨论】:

  • 属性和expando对象的组合确实有效。非常感谢。
  • 我很高兴它成功了!顺便说一句,我相信如果您使用 ExpandoObject 方式,我认为您不需要任何 Firestore 属性,除非您在另一个地方正常转换它。我建议只使用 Firestore 属性,但在某些情况下它不起作用。
  • ExpandoObject 为我工作。它比使用自定义转换器更容易。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-14
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多