I want to subclass a Class in Parse that has Pointers to other classes.
Here is my class:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Parse;
using System.Threading.Tasks;
[ParseClassName("UserCars")] public class UserCars : ParseObject {
[ParseFieldName("car")]
public Car car
{
get { return GetProperty<Car>("car"); }
set { SetProperty<Car>(value, "car"); }
}
[ParseFieldName("isBumpers")]
public bool isBumpers
{
get { return GetProperty<bool>("isBumpers"); }
set { SetProperty<bool>(value, "isBumpers"); }
}
When I execute this query below isBumpers returns an accurate bool value, but car is always null:
var query = new ParseQuery<UserCars>();
query.WhereEqualTo("user", ParseUser.CurrentUser);
query.FindAsync().ContinueWith(t =>
{
IEnumerable<UserCars> userCars = t.Result;
foreach (UserCars u in userCars)
{
Debug.Log(u.car);
}
});
I tried adding this with no change:
IEnumerable<UserCars> userCars = t.Result;
foreach (UserCars u in userCars)
{
Task<Car> fCar = u.car.FetchIfNeededAsync();
Debug.Log(u.car);
}
What am I missing?
fCar is a Task, so basicly you should wait for it to complete.
Try writing this instead:
foreach (UserCars u in userCars )
{
u.car.FetchIfNeededAsync().ContinueWith(result =>
{
Debug.Log(u.car);
};
}
This will make sure you wait for the data to be correctly fetched.
Related
i have a script MenuManager.cs amd i this script i get tow doc in the firebase firestone, and this works well but when i will set the result in a text, dont work
using Firebase.Firestore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Json;
using UnityEngine;
public class MenuManager : MonoBehaviour
{
private Usuario usuario;
private Rank rank;
private CollectionReference usuarioCollection;
private CollectionReference rankCollection;
public GameObject rankNomeLabel;
public bool infoCarregadas;
public GameObject botaoInfo;
void Start()
{
this.rank = new Rank();
this.botaoInfo.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => this.CarregaInfos());
//this.infoCarregadas = false;
}
void Update()
{
/*if (db != null && infoCarregadas == false)
{
this.CarregaInfos();
} else
{
if (infoCarregadas == false)
{
db = FirebaseAuthenticator.instance.fsDB;
}
}*/
}
private void CarregaInfos()
{
try
{
FirebaseFirestore db = FirebaseAuthenticator.instance.fsDB;
var usuarioJson = PlayerPrefs.GetString("usuario");
this.usuario = usuarioJson != "" ? JsonUtility.FromJson<Usuario>(usuarioJson) : null;
if (this.usuario != null && this.usuario.UID != null)
{
this.usuarioCollection = db.Collection("usuario");
DocumentReference docRef = this.usuarioCollection.Document(usuario.UID);
docRef.GetSnapshotAsync().ContinueWith(task =>
{
DocumentSnapshot snapshot = task.Result;
if (snapshot.Exists)
{
Dictionary<string, object> usuario = snapshot.ToDictionary();
foreach (KeyValuePair<string, object> pair in usuario)
{
if (pair.Key == "rank")
{
this.rankCollection = db.Collection("rank");
DocumentReference docRef = this.rankCollection.Document(pair.Value.ToString());
docRef.GetSnapshotAsync().ContinueWith(task =>
{
DocumentSnapshot snapshot = task.Result;
if (snapshot.Exists)
{
Dictionary<string, object> rank = snapshot.ToDictionary();
foreach (KeyValuePair<string, object> pair in rank)
{
if (pair.Key == "nome")
{
this.rankNomeLabel.GetComponent<UnityEngine.UI.Text>().text = pair.Value.ToString();
}
}
}
else
{
Debug.Log("Erro ao carregar o rank: " + snapshot.Id);
}
});
}
}
}
else
{
Debug.Log("Erro ao carregar o usuário: " + snapshot.Id);
}
});
}
else
{
Debug.Log("Erro ao pegar usuário do PlayerPrefs");
}
}
catch (Exception e)
{
Debug.LogError("Erro: " + e);
}
}
}
the text is linked to the variable (print bellow)
this.rankNomeLabel.GetComponent<UnityEngine.UI.Text>().text = pair.Value.ToString(); in this line, the reference is null
think the problem is in setting the value within the async method but I don't know how to fix it
does anyone know what's going on?
Most of the Unity API can only be used on the Unity main thread (the exception are pure structs since they are only data containers and don't immediately rely on or influence the actual scene).
ContinueWith is not guaranteed to be executed in the main thread.
Therefore Firebase provides the Extension method ContinueWithOnMainThread.
Replacing both or at least the inner ContinueWith by ContinueWithOnMainThreae should solve your issue or at least make it clearer where the actual issue is.
Instead of using GetComponent over and over again make your live easier and directly use the correct types
using UnityEngine.UI;
...
public Text rankNomeLabel;
public Button botaoInfo;
this also makes sure you can only drag in objects that actually have the according component attached and is less error prone on runtime since it makes already sure it isn't null - and if it is (e.g. if the object was destroyed) you can also see it immediately in the Inspector
I solved a similar issue by checking a boolean in an update method. It's not fancy but it works.
public class MyClass : MonoBehaviour
{
private bool updateUI = false;
private async Task function() {
updateUI = true;
}
private void Update() {
if (updateUI) {
// update your ui here
...
updateUI = false;
}
}
}
In my project, I am using FluentValidation of .net. Class on which I applied this validation is something like this:
[Validation(typeof(InputValidator))]
public class Inputs
{
public IEnumerable<string> MobileNos { get; set; }
}
InputValidator.cs file is something like this
public class InputValidator: AbstractValidator<Inputs>
{
public BlockMobileInputsValidator()
{
RuleFor(x => x.MobileNos).Cascade(CascadeMode.StopOnFirstFailure).NotEmpty()
.Must(x => x.Count() <= 100).WithMessage("List should not contain more than 100 mobile numbers.")
.SetCollectionValidator(new MobileValidator());
}
}
And MobileValidator.cs
public class MobileValidator:AbstractValidator<string>
{
public Mobilevalidator()
{
RuleFor(x => x).Matches("^[6789]\d{9}$").WithMessage("{PropertyValue} is not in correct mobile-number format");
}
}
Now when I pass {null,"7897897897"} list to MobileNos of Input class, it is not giving any error and list is accepted for further use.
I am not able to understand this strange behaviour. I also tried this
public class MobileValidator:AbstractValidator<string>
{
public Mobilevalidator()
{
RuleFor(x => x).NotNull().Matches("^[6789]\d{9}$").WithMessage("{PropertyValue} is not in correct mobile-number format");
}
}
but this also not working for above Input.
Can anyone tell why it is accepting null value?
I don't know why your code does not work but when you change InputValidator.cs to the following code, then you can get the desired result:
using FluentValidation;
using System.Linq;
public class InputsValidator : AbstractValidator<Inputs>
{
public InputsValidator()
{
RuleFor(x => x.MobileNos).Cascade(CascadeMode.StopOnFirstFailure).NotEmpty()
.Must(x => x.Count() <= 100).WithMessage("List should not contain more than 100 mobile numbers.");
RuleForEach(x => x.MobileNos).NotNull().SetValidator(new MobileValidator());
}
}
Then the following test passes:
using FluentValidation;
using Xunit;
using System;
using System.Collections.Generic;
namespace test
{
public class InputsValidatorTests
{
[Fact]
public void WhenContainsNull_ThenIsNotValid()
{
var inputs = new Inputs();
inputs.MobileNos = new List<string>() { null, "7897897897" };
var inputsValidator = new InputsValidator();
var result = inputsValidator.Validate(inputs);
Assert.False(result.IsValid);
}
}
}
Good time of the day!
I'm trying to pass few classes, which inherit from one base class.
The structure looks as follows:
Permission Class - Permisions for user
Edit : Permission - Ability to edit record
Delete : Permission - Ability to delete record
Create : Permission - Ability to create record
User Class - User class
private Permission[] permissions - permissions available for user
public void AddDefaultPermissions(Permission[] permissions)
What i can't figure out, is how to pass multiple permissions to this function and check if permission has already been added. What i was thinking of is to allow something like the following method call:
AddDefaultPermissions(Edit, Delete, Create);
Permission Class:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Permission {
private int permissionID;
private string permissionName;
private string permissionDescription;
private int accessStartTimestamp;
private int accessEndTimestamp;
public int PermissionID {
get { return permissionID; }
set { permissionID = value; }
}
public string PermissionName {
get { return permissionName; }
set { permissionName = value; }
}
public string PermissionDescription {
get { return permissionDescription; }
set { permissionDescription = value; }
}
public int AccessStartTimestamp {
get { return accessStartTimestamp; }
set { accessStartTimestamp = value; }
}
public int AccessEndTimestamp {
get { return accessEndTimestamp; }
set { accessEndTimestamp = value; }
}
}
Edit Class:
using System;
using System.Collections;
using System.Collections.Generic;
public class Edit : Permission {
public Edit() {
PermissionID = 1;
PermissionName = "Edit";
PermissionDescription = "Allow user to edit records";
AccessStartTimestamp = 1488369600;
AccessEndTimestamp = 1491048000;
}
}
For checking if permission is already exists, PermissionID variable can be used. This variable is inherited by all of the permission classes and unique for the permission (Edit = 1, Create = 2, Delete = 3);
I saw some examples with LINQ, but couldn't make it to work, since actually never worked with LINQ.
Is it possible to achieve this functionality + to check if permission has already been added to avoid duplicates?
You can easily eliminate the duplicaets from your input using Distinct:
AddDefaultPermissions(params Permission[] permissions)
{
var actualPermissions = permissions.Distinct();
}
This assumes your Permission-class implements Equals and GetHashCoe appropriately by comparing their PermissionID-property, e.g:
class Permission
{
public override bool Equals(object obj)
{
var p = obj as Permission;
if(p == null) return false;
return this.PermissionID == p.PermissionID;
}
public override int GetHashCode()
{
return this.PermissionID .GetHashCode();
}
}
If you can´t change the implementation of this class you can also use your own implementation for IEqualityComparer within Distinct:
var actualPermissions = permissions.Distinct(myEqualityComparer);
If you just want to check if the item was allready added you can just check for a Contains which will rely on Equals to be implemented as shown above:
AddDefaultPermissions(params Permission[] permissions)
{
var actualPermissions = permissions.Distinct();
foreach(var p in permissions)
if(!listOfAllreadyAddedPermissions.Contains(p)
listOfAllreadyAddedPermissions.Add(p);
}
Or alternativly again - if you don´t want to change the class - use Any:
if(!listOfAllreadyAddedPermissions.Any(x => x.PermissionId == p.PermissionId)
listOfAllreadyAddedPermissions.Add(p);
You can pass an arbitrary number of permissions using params syntax:
AddDefaultPermissions(params Permission[] permissions) {
}
To check which permission is used more than once, group and check counts:
foreach (var pg in permissions.GroupBy(p => p).Where(g => g.Count() > 1) {
Console.WriteLine("Permission {0} is used {1} times.", pg.Key, pg.Count());
}
Important: the above will work only if Permission class properly implements Equals and GetHashCode methods.
Following is the code for which the error is being generated:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Neo4jClient;
using Neo4jClient.Cypher;
namespace ConsoleApplication1
{
public class SNode
{
public int shelfid { get; set; }
public int floorid { get; set; }
}
public class PathsResult<TNode>
{
public IEnumerable<Node<TNode>> Nodes { get; set; }
public IEnumerable<RelationshipInstance<object>> Relationships { get; set; }
}
class Program
{
public static PathsResult<SNode> getPath(int sourceShelfId, int destinationShelfId, GraphClient client)
{
var pathsQuery =
client.Cypher
.Match("p = shortestPath((src:Node)-[*..150]-(dest:Point))")
.Where((SNode src) => src.shelfid == sourceShelfId)
.AndWhere((SNode dest) => dest.shelfid == destinationShelfId)
.Return(p => new PathsResult<SNode>
{
Nodes = Return.As<IEnumerable<Node<SNode>>>("nodes(p)"),
Relationships = Return.As<IEnumerable<RelationshipInstance<object>>>("rels(p)")
});
var res = pathsQuery.Results;
return res;
}
}
}
The error I'm receiving is that:
Cannot implicitly convert type System.Collection.Generic.IEnumerable<ConsoleApplication1.PathResult<ConsoleApplication1.SNode> >
to ConsoleApplication1.PathResult<ConsoleApplication1.SNode> >. An explicit conversion exists, are you missing a cast?
From what I understand pathQuery.result should return a single PathResult object. However, I tried to make a cast according to the above error like this:
var res = pathsQuery.Results.AsEnumerable<PathsResult<SNode> >;
And now the new error it gives is:
Cannot assign method group to implicitly-typed local variable
Where am I going wrong?
You have several possibilites:
change return type of getPath to IEnumerable...
Use only first element of the query result: Add .FirstOrDefault()
var res = pathsQuery.Results.FirstOrDefault();
Generally it is a good idea to set a breakpoint and put the mouse over var to inspect what type it is. Even better to avoid var in such cases and make the compiler report all problems.
I don't understand how to fix this issue. I will need your help and explanation on how to fix it.
I used a WebService to populate a DropDownList with artist names.
Here is the code behing.
private List<ArtistServiceReference.ArtistServiceClient> ArtistDetail()
{
ArtistServiceReference.ArtistServiceClient client =
new ArtistServiceReference.ArtistServiceClient();
ArtistServiceReference.Artist[] artists = client.ArtistDetail();
return artists.ToList(); <=== errror here
Cannot implicitly convert type System.Collections.Generic.List<ArtistServiceReference.Artist> to System.Collections.Generic.List<ArtistServiceReference.ArtistServiceClient>
Here is the ArtistService.cs
public class ArtistService : IArtistService
{
public List<Artist> ArtistDetail()
{
using (ArtistDataContext db = new ArtistDataContext())
{
return (from artist in db.Artists
select new Artist()
{
Id = artist.Id,
Artist_nom = artist.Artist_nom
}).ToList();
}
}
}
If you want your client method to return a list of Artists, why do you declare it as returning a list of ArtistClients?
The following should fix your issue:
private List<ArtistServiceReference.Artist> ArtistDetail()
{
...
return artists.ToList();
}
or, even more elegant:
using YourNamespace.ArtistServiceReference;
private List<Artist> ArtistDetail()
{
...
return artists.ToList();
}
Your return type on your method should be a list of ArtistServiceReference.Artist as opposed to a list of ArtistServiceReference.ArtistServiceClient. You want to return a list of Artists by using the ArtistServiceClient, you are not returning a list of the clients.
private List<ArtistServiceReference.Artist> ArtistDetail()
{
ArtistServiceReference.ArtistServiceClient client =
new ArtistServiceReference.ArtistServiceClient();
var artists = client.ArtistDetail();
return artists.ToList();
}
here is the solution:
code behind.cs
private List<ArtistServiceReference.Artist> ArtistDetail()
{
ArtistServiceReference.ArtistServiceClient client = new
ArtistServiceReference.ArtistServiceClient();
ArtistServiceReference.Voiture[] artists = client.ArtistDetail();
return artists.ToList();
}
ArtistService.cs
public class ArtistService : IArtistService
{
public List<Artist> ArtistDetail()
{
using (ArtistDataContext db = new ArtistDataContext())
{
return db.Artists.ToList();
}
}
}