How to create object affinity in Apache Ignite? - memcached

I am a beginner in Apache Ignite. I have 3 java classes ClassA, ClassB, and ClassC.
ClassA{
int idA; //unique
String stringA;
public ClassA(){}
public ClassA(int idA,String stringA){
this.idA=idA;
this.stringA=stringA;
}
public int getidA(){
return idA;
}
public String getstringA(){
return stringA;
}
}
ClassB{
int idB; //unique
String stringB;
public ClassB(){}
public ClassB(int idB,String stringB){
this.idB=idB;
this.stringB=stringB;
}
public int getidB(){
return idB;
}
public String getstringB(){
return stringB;
}
}
ClassC{
int idC,idB; //idC unique. idB from ClassB
String stringC;
public ClassC(){}
public ClassB(int idB,int idC,String stringC){
this.idB=idB;
this.idC=idC;
this.stringC=stringC;
}
public int getidC(){
return idC;
}
public String getstringC(){
return stringC;
}
}
Lemme tell an example. I want ClassA in replicated mode and B & C in partitioned modes. ClassC is related to ClassB. The id of ClassB is present in ClassC (acting like a foreign key). Say, I have 3 nodes, 30 ClassA objects, 30 ClassB objects and 30 ClassC objects. They are distributed in nodes like below;
Node 1 => ClassA->30, ClassB->10,ClassC->8
Node 2 => ClassA->30, ClassB->5,ClassC->3
Node 3 => ClassA->30, ClassB->15,ClassC->19
Objects of ClassC related to ClassB should present in same node. I know that there is some mechanism AffinityKey, but I don't know how to implement this.

All you need to do is collocate Class C with Class B based on ID of Class B. In Apache Ignite it is called Affinity Collocation and is described in detail here: https://apacheignite.readme.io/docs/affinity-collocation
In particular, in your case, you should attach #AffinityKeyMapped annotation to ClassC.idB field.
Also, more info on PARTITIONED and REPLICATED caches here:
https://apacheignite.readme.io/docs/cache-modes
Once you configure your caches this way, you can also use SQL to query them, including distributed SQL joins. More on SQL here:
https://apacheignite.readme.io/docs/sql-queries

Related

Entity Framework Set with Generic Class

Ok, I might be punching above my pay grade here, but I'm trying to create a generic CRUD routine for and EF project. I've got most of it working but I'm flailing around on one point.
Normally you do something like this to add an entity through a context-
DBContext.MyClass.Add( p ); // p = instance of MyClass
That works fine, but since in a global method to handle all adds regardless of what class they are I'm passing in a Model as an object it would look more like this-
DBContext<whateverobject>.Add(whateverobject); // my objects is an object param passed into the method
I've tried doing a bunch of typeofs and there where T : class stuff but I'm having no luck. Any pointing in the right direction would help me out.
I'm using EF Core 2 so my options might also be more limited than EF 6.
Thanks.
The method you're looking for is DbContext's Set<T>()
Your generic repository for your generic CRUD would look something like this:
public class Repo<T> where T: class
{
private readonly DbSet<T> _set;
public Repo(DbContext dbContext)
{
_set = dbContext.Set<T>();
}
public void Add(T entity) => _set.Add(entity);
}
This example includes a maybe unusual thing:
where T: class: we have to specify that T has to be a reference type because DbSet<T> expects T to be a reference type
For generic querying you might want to use extension methods.
In order to implement a ById method you'd have to specify that the type T must have an Id property using an interface. That would look something like this:
public interface IEntity
{
int Id { get; set; }
}
public class User : IEntity
{
public int Id { get; set; }
}
public static class DbSetExtensions
{
public static T ById<T>(this DbSet<T> dbSet, int id) where T: class =>
dbSet.FirstOrDefault(entity => entity.Id == id);
}

Create a table corresponding to enum Entity framework

I followed the below answer to insert enums into database;
How to create a table corresponding to enum in EF6 Code First?
But I am facing one strange issue. Every time I run the application, it additionally enters the last enum. For example, suppose i have three option for enum;
Started, In Progress, Done.
now on first run, it enters the 3 values as expected.
but on second run, there are four rows in database and Done is duplicated. Done is duplicated on each run.
PS:
I have done some changes from above article.
I used DatabaseGenerated(DatabaseGeneratedOption.Identity) instead of DatabaseGenerated(DatabaseGeneratedOption.None)
My table is already in database
I am using code-first approach and just wanted to re-factor code.
Am I doing anything wrong or is there any other solution to solve this?
Enum Class:
namespace ToDO.Data.Models
{
public class TaskStatus
{
private TaskStatusTaskStatusEnum #enum)
{
Id = (int)#enum;
Name = #enum.ToString();
Description = #enum.GetEnumDescription();
}
protected TaskStatus() { } //For EF
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string Description { get; set; }
public static implicit operator TaskStatusTaskStatusEnum #enum) => new TaskStatus(#enum);
public static implicit operator TaskStatusEnumTaskStatus status) => (TaskStatusEnum)status.Id;
}
public enum TaskStatusEnum
{
[Description("Started")]
Started,
[Description("In Progress")]
InProgress,
[Description("Done")]
Done
}
}
EF Extenstion method to add values in database:
public static void SeedEnumValues<T, TEnum>(this IDbSet<T> dbSet, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => dbSet.AddOrUpdate(instance));
Result:
Database result
Thanks.
The AddOrUpdate does its compare with the primarykey. Enums starts from 0. This one is not in the database so it is added again. You can use AddOrUpdate(x=>x.Code.. etc

Very generic CreateOrUpdate method with Entity Framework

I created a generic repository class that all my other repository classes are inheriting from. This is great, because it means almost all the plumbing is done one time for all repositories. I put a full explanation of what I'm talking about here, but here is the code for my GenericRepository (some code is removed for brevity):
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, new()
{
private IMyDbContext _myDbContext;
public GenericRepository(IMyDbContext myDbContext)
{
_myDbContext = myDbContext;
}
protected IMyDbContext Context
{
get
{
return _myDbContext;
}
}
public IQueryable<T> AsQueryable()
{
IQueryable<T> query = Context.Set<T>();
return query;
}
public virtual void Create(T entity)
{
Context.Set<T>().Add(entity);
}
public virtual void Update(T entity)
{
Context.Entry(entity).State = System.Data.EntityState.Modified;
}
}
As you see, I have a Create method and an Update method. It would be very convenient to have a "CreateOrUpdate" method, so I don't have to manually check for existing objects each time I have to save something to the database.
Each of my objects in Entity Framework have an "Id", but the challenge here is that the GenericRepository works with "T".
Now, with that rather long introduction, to my specific question.
How do I create a generic CreateOrUpdate method for my GenericRepository?
UPDATE
After Marcins response, I implemented the following generic methods in my GenericRepository. It will take some time before I can test that it works as expected, but it looks very promising.
public virtual bool Exists(Guid id)
{
return Context.Set<T>().Any(t => t.Id == id);
}
public virtual void CreateOrUpdate(T entity)
{
if (Exists(entity.Id))
{
var oldEntity = GetSingle(entity.Id);
Context.Entry(oldEntity).CurrentValues.SetValues(entity);
Update(oldEntity);
}
else
{
Create(entity);
}
}
The code above has no less than 3 roundtrips to the database when updating. I'm sure it can be optimized, but it wasn't really the exercise for this question.
This question handles that topic better:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key
Create a interface with Id property, implement it on every of your entities and add another generic constraint to your class:
public interface IEntity
{
int Id { get; set;}
}
And
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, IEntity, new()
With that, you'll be able to use Id property within your generic repository class.
Of course - Id don't have to be an int, it can be Guid as well.

MVC4 and Entity Framework Inheritance and Include

I have some simple objects
public class DataClass
{
public int id;
public string Data;
}
public class Job()
{
public int id;
}
public class NewJob : Job
{
public DateTime StartDate;
public DataClass data;
}
I have then defined them in my dBContext()
public DbSet<Job> Jobs { get; set; }
public DbSet<DataClass> DataClass { get; set; }
Now if I use the following code
NewJob job = (NewJob) db.Jobs.Find(id);
This works fine but returns "data" as null
I know I define the class with the virtual keyword and it works and populates the "data" object.
public class NewJob : Job
{
public DateTime StartDate;
public virtual DataClass data;
}
But in my case I "normally" do not want the "data" object to be populated. So I need to load it on demand.
If I try something like
NewJob job = (NewJob)db.Jobs.Include("data").First();
I get an exception
A specified Include path is not valid. The EntityType 'Models.Job' does not declare a navigation property with the name 'data'.
I guess this is because it is looking at "job" and not "NewJob" when it is trying to do the include.
I also do not like the include with a string - no design time checking.
It looks like you are trying to convert data object to your domain object via type casting which is a very bad idea. What you want to do is grab your data object, instantiate your domain object, and map your data values to the domain object using some type of helper class. A very helpful tool I have been using is Automapper. Its a tool that will allow you to map one object to another. It also allows the use of regular expression to help with the mappings if the naming conventions between the 2 objects are different.
If you're using Entity Framework Code First and want to create instances of derived classes/entities you should do the following:
using (var db = new MyDbContext())
{
var newJob = db.Jobs.Create<NewJob>();
newJob.data.Data = "some data for a new job"; // this is string Data from DataClass
db.Jobs.Add(newJob);
db.SaveChanges();
}
After a lot of searching I found the following which can help.
If you include the System.Data.Entity namespace in your using clause then you can use the extension method .Include() after OfType<>() which is not normally available.
Slightly different code sample
using System.Data.Entity;
NewJob job = (NewJob)db.Jobs.OfType<NewJob>().Include(m => m.data).Where(x => x.id == id).FirstOrDefault();
This seems to be working for me in the example I used.

Entity Framework code first Inheritance Issue

I have code first implementation for flowing hierarchy,
BaseContact{
Public int Id{get;set;}
public string Name{get;set;}
//..
}
Person:BaseContact{
public string Designation{get;set;}
//..
}
Company:BaseContact{
public int NumOfEmployees{get;set;}
//..
}
I want to identify person or company with by using only the Id value? Currently I am using reflection to identify whether it is a person or company. Is there any other way to identify it without doing too much?
Without seeing how you initialised your classes I'm going to assume you have a table per concrete type approach.
You can't do it just from the ID, as you don't know which table the ID belongs to. ID 2 in "Person" table is a different entity to ID 3 in "Company". The only practical way to identify only from an ID is using a Table per Hierarchy approach and inspecting the type descriptor.
Some good references
http://weblogs.asp.net/manavi/archive/2011/01/03/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines.aspx
http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx
You can also use a simple is statement instead of reflection. Ie if (entity is Company)
In your BaseContact (assume it is an abstract class) add abstract property which will be implemented by other two classes.Use Enum to identify the property type as follows.
public enum MyType
{
Person,
Company,
};
public abstract class BaseContact{
public abstract MyType ContactType{get;}
}
public class Person:BaseContact
{
public override MyType ContactType
{
get
{
return MyType.Person;
}
}
}
public class Company:BaseContact
{
public override MyType ContactType
{
get
{
return MyType.Company;
}
}
}
Use your BaseContact repository to retrieve entities and use enum for type separation.