Can't seem to get OneToMany relation working - c#

I'm very new to Mobile App Development so i'm trying to teach myself.
I'm using Xamarin and sqlite-net (extensions) for this particular app i'm trying to make.
I have 2 classes with a OneToMany relationship
class Game
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<Player> Players { get; set; }
public Game()
{
Players = new List<Player>();
}
}
class Player
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[MaxLength(8)]
public string Name { get; set; }
[ForeignKey(typeof(Game))]
public int GameId { get; set; }
[ManyToOne]
public Game Game { get; set; }
}
Now in my activity I have something like this
SQLiteConnection db = new SQLiteConnection(new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid(), path);
db.CreateTable<Player>();
db.CreateTable<Game>();
Game game = new Game();
game.Name = "Stupid game";
Game game2 = new Game();
game2.Name = "Fun game";
Game game3 = new Game();
game3.Name = "Amazing game";
db.Insert(game);
db.Insert(game2);
db.Insert(game3);
Player player = new Player();
player.Name = name; //Getting this from a input field
db.Insert(player);
Random random = new Random();
player.GameId = random.Next(1, 3);
Game game = db.Get<Game>(player.GameId);
player.Game = game;
db.UpdateWithChildren(player);
game.Players.Add(player);
db.UpdateWithChildren(game);
This all seems to work and gives me no errors. When I debug this I can see that the player is indeed added with a Game. However when I try somewhere else to get all the players using the following statement,
List<Player> players = db.Table<Player>().ToList();
they suddenly don't have a Game anymore and my program crashes when I try to read that property.
I've tried a few different things with the UpdateWithChildren and InsertWithChildren but to no avail. Is there something I'm doing wrong or is it something I haven't installed or?
I really appreciate the help.

The thing about sqlite-net extensions is that you cannot go "Back" to using regular sqlite-net methods if you want to obtain children relationships. Thus you will have to follow their documentation here:
https://bitbucket.org/twincoders/sqlite-net-extensions
They provide methods such as GetChildren, UpdateWithChildren, etc in which you will have to use over the generic db.Table<T> methods.
If you decide to use the recursive methods, be sure to provide the optional recursive parameter.
Thus you should be able to do something along the lines of:
conn.GetWithChildren<Player>(identifier, recursive: true)
Otherwise read up more on the Cascade Operations section of the documentation linked above.

Related

How do i add multiple markers in xamarin using for each loop with a list model

I am trying to add pins on my Xamarin android application. I have already set up the map and I need to create pins from a list array that contains the latitudes and longitudes. I know it's quite simple but I'm stuck here.
Below is my sample code.
public class Farmers
{
public int farmers_id { get; set; }
public string Farmer_name { get; set; }
public double Long { get; set; }
public double Lat { get; set; }
}
private void AddMarker()
{
List<Farmers> farmers =GetFarmers();
foreach (Farmers p in farmers)
{
//HOW TO ADD NEW PINS FOR EACH FARMER ON THE MAP WITH FARMER NAME AS LABEL
}
}
I'm using Xamarin.Forms.Maps. The issue is more of how to loop.
create a pin and add it to the map
foreach (Farmers p in farmers)
{
var pin = new Pin();
pin.Label = p.Farmer_name;
pin.Type = PinType.Place;
pin.Position = new Position(p.Lat,p.Long);
myMap.Pins.Add(pin);
}

How to save a reference to a previous version of an object in mongo DB

I am trying to get started with MongoDB. I am used to working with relational database engines but now I have to work with MongoDB per requirement.
I am trying to explain my general problem as simplified as possible. Imagine being a Person. You have some traits like a name or some friends. Now you have died of old age and been born as a new human. You now could have a different name and different friends.
Now you don't like your new "You" and want to return to a previous version of yourself, maybe because you liked the name or the friends more.
To allow this, a Person is bound to a Soul which just stores the current Person as well as all your previous ones.
Now when you store this object in MongoDB you get pretty fast a very huge document (More than 13k Lines in my case). I have created a similar JSON structure to highlight the problem.
"Souls:" {
"UniqueId": {
"CurrentPerson": {
"Name": "Jane Doe",
"PreviousLifePerson": {
"Name": "John Doe",
"PreviousLifePerson": {
"Name": "Max Mustermann",
"PreviousLifePerson": {
"Name": "Erika Mustermann",
"PreviousLifePerson": null
}
}
}
}
}
}
I have read that MongoDB saves related objects as embedded document by default.
The solution to this problem will probably be to save relations by the id of an object. However I am still unsure on if this is really the best solution and additionally I have some questions about general best practices for the .NET MongoDB Driver.
In C# I would propably have a class like this then:
public class Person
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("Name")]
public string Name { get; set; }
[BsonElement("Friends")]
public List<ObjectId> FriendIds { get; set; }
[BsonIgnore]
public List<Person> Friends { get; set; }
[BsonElement("Reincarnation")]
public int Reincarnation { get; set; }
[BsonElement("PreviousLifePerson")]
public ObjectId PreviousLifePersonId { get; set; }
[BsonIgnore]
public Person PreviousLifePerson { get; set; }
}
For each Ignored Element I'd have to send an additionally query to the database and retrieve those elements. Is this right?
Would I have for Soul and Person an individual collection then, even if a person is always assigned to a soul?
There surely is no built-in way to deserialize an object from the database without explicitly specifying the object id as a property, is it?
since this is a highly relational problem domain, i would do it with MongoDB.Entities convenience library. here's a full program covering all the bases you mentioned.
using MongoDB.Entities;
using System.Linq;
namespace StackOverflow
{
public class Program
{
public class Soul : Entity
{
public Many<Person> Incarnations { get; set; }
public One<Person> CurrentIncarnation { get; set; }
public Soul() => this.InitOneToMany(() => Incarnations);
}
public class Person : Entity
{
public string Name { get; set; }
public One<Soul> Soul { get; set; }
public One<Person> PreviousLife { get; set; }
public Many<Person> Friends { get; set; }
public bool IsDead { get; set; } = false;
public Person() => this.InitOneToMany(() => Friends);
}
static void Main(string[] args)
{
new DB("test");
//big bang
var god = new Soul();
god.Save();
//first man is born
var adam = new Person
{
Name = "Adam",
Soul = god.ToReference()
};
adam.Save();
god.Incarnations.Add(adam);
god.CurrentIncarnation = adam.ToReference();
//first woman is born (without a soul ;p)
var eve = new Person
{
Name = "Eve",
};
eve.Save();
//adam and eve become friends under an apple tree
adam.Friends.Add(eve);
eve.Friends.Add(adam);
//adam dies and comes back as sally
adam.IsDead = true; adam.Save();
var sally = new Person
{
Name = "Sally",
Soul = god.ToReference(),
PreviousLife = adam.ToReference()
};
sally.Save();
god.CurrentIncarnation = sally.ToReference();
god.Incarnations.Add(sally);
//sally and eve feel a deep connection
sally.Friends.Add(eve);
//sally feels stuck in a mans body, so she goes back to being adam
sally.IsDead = true;
sally.Save();
god.CurrentIncarnation = adam.ToReference();
god.Save();
adam.IsDead = false;
adam.PreviousLife = sally.ToReference();
adam.Save();
//invite sally's friends to the funeral
var guestlist = DB.Find<Person>().One(sally.ID)
.Friends.Collection()
.ToList();
}
}
}
the library stores relationships by using special join collections which are automatically indexed which makes queries extremely fast.
my personal rule of thumb is to not embed an object inside another if there's gonna be more than a handful of them in there. but it all depends on how your app queries the data, what data is needed by your apps views. with MongoDB.Entities you have the freedom to do both quite easily.

Class Instance or Inherited Class for a game? Best Practice

So I'm building a small game framework to reinforce abstract classes and interfaces. I've been building classes for some mechanics and I'm not sure how to deal with the final pieces.
Here's the class framework (with some miscellaneous methods removed):
public abstract class Ability
{
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual string Type { get; set; }
public virtual string Stat { get; set; }
public virtual float Scale { get; set; }
public virtual float MPCost { get; set; }
public virtual float SPCost { get; set; }
}
public class Attack : Ability
{
public float BaseDmg { get; set; }
public bool isUnblockable { get; set; }
public float GetDmg(int stat)
{
return BaseDmg * (1 + stat * Scale);
}
}
Now for the actual Attacks I want to create, should I instantiate like I have been?
public static class AllAttacks
{
//Physical Attacks
public static Attack slash = new Attack();
//Magical Attacks
public static Attack push = new Attack();
public static void Generate()
{
//Physical Attacks
slash.Name = "Slash";
slash.Description = "A simple but effective strike.";
slash.Type = "physical";
slash.Stat = "str";
slash.Scale = 0.1F;
slash.MPCost = 0;
slash.SPCost = 1;
slash.BaseDmg = 5;
slash.isUnblockable = false;
//Magical Attacks
push.Name = "Push";
push.Description = "A powerful telekinetic strike.";
push.Type = "magic";
push.Stat = "int";
push.Scale = 0.1F;
push.MPCost = 1;
push.SPCost = 0;
push.BaseDmg = 5F;
push.isUnblockable = false;
}
Or should I actually create a new inherited class for each unique item and then instantiate them in the Fight class? And if I do, should these be static or non-static?
public class Slash : Attack
{
//Code Here
}
Could anyone point me to best practices or what the most efficient method would be?
Typically there are two main reasons to define a new class: new behavior and/or new contract, that is changed implementation for the former reason or added new public members for the latter. Now considering your example I don't see changed contracts or behaviors for various types of attack (only changed state) so I don't see a reason to define new classes for them. From the readability standpoint the Generate method isn't optimal however - I'd create separate methods for different types of attack which would clearly denote what type of attack they create.
As for the instantiation aspects, if you aren't going to mutate your attack instances than get them created in the single place is pretty okay, otherwise you need to control the life cycle of every attack instance on the level where the instance is used.

C# base class have a derived class member and it loops

I have this class:
public class GameData
{
public int[,] mat { get; set; }
public int dim { get; set; }
public int goal { get; set; }
public Game game { get; set; }
public GameData()
{
game = new Game();
}
}
And this two other derived classes:
public class Game :GameData
{
private Mover m;
public Game()
{
dim = 4;
goal = 16;
mat = new int[dim, dim];
m = new Mover();
}
/*Methods*/
}
public class Mover : GameData
{
/*Methods*/
}
It loops because Game constructor calls GameData constructor and so on.
How can I do?
I am starting whit OOP programming and I am not sure this three classes are the best way to set the program. GameData contains common datas, Game contains the method to play and Mover contains a group of method used by Game
Honestly inheritance doesn't make any sense here. Inheritance is an "is a type of" relationship (in other words, is Game a type of GameData? I doubt it.
Instead use composition! Just have class hold the objects they care about. Composition is a "has a" relationship, which makes a lot more sense in your case. Honestly, I would invert the Game/GameData relationship, a Game probaly holds GameData; not the other way around. Only you know what you need though.
public class GameData
{
public int[,] mat { get; set; }
public int dim { get; set; }
public int goal { get; set; }
public Game game { get; set; }
public GameData()
{
game = new Game();
dim = 4;
goal = 16;
mat = new int[dim, dim];
}
}
public class Game
{
private Mover m;
public Game()
{
m = new Mover();
}
/*Methods*/
}
public class Mover
{
/*Methods*/
}
This sentence
public GameData()
{
game = new Game();
}
makes no sense; as GameData is the parent, is not logical to have a child inside the parent. Obviously that makes a loop, as you are creating a Game : GameData over and over with that sentence.
Think about inheritance you want, as you are using it incorrectly with Mover too.
Well you definitely have a circular reference which is a design smell. You could stop the infinite loop by checking for null:
public GameData()
{
if(game == null)
game = new Game();
}
Or pass the Game instance in to the constructor rather than creating a new one - hard to say what's correct without knowing more of your overall design.

Linq - Select rows which are on lists

I have got table "Actions" which has fields like Player, Game, Type - ale connected with other tables. I have also two Lists in my c# code:
List<Player> playersForStats
List<Game> gamesForStats
Now i want to select a rows from Actions which (field)Players are in list playersForStats and (field)Game are in list gamesForStats. How can I make it using linq? I have to use inner join or something else?
Something like this should work if your object has proper equals method:
var oActions = ..
var oData = oActions.Where(c=> c.Players.TrueForAll(p => playersForStats.Contains(p)) && gamesForStats.Contains(c.Game));
Assuming that c.Players is List And c.Game is Field.
I'd assume your action list named as actions:
actions.Where(x=>playersForStats.Contains(x.Player) && gamesForStats.Contains(x=>x.Game));
In fact just need to search if playersForStats and gamesForStats contains related action's player and game.
Something like this :
class Program
{
static void Main(string[] args)
{
List<Action> actions = new List<Action>();
List<Game> gamesForStats = new List<Game>();
List<Player> playersForStats = new List<Player>();
List<Action> result = (from oAction in actions
join game in gamesForStats on oAction.Game equals game.GameName
join player in playersForStats on oAction.Player equals player.PlayerName
select oAction).ToList();
Console.ReadLine();
}
}
public class Player
{
public string PlayerName { get; set; }
}
public class Game
{
public string GameName { get; set; }
}
public class Action
{
public string Player { get; set; }
public string Game { get; set; }
public string Type { get; set; }
}

Categories