EF Core and Collection ordering by specified column: move up and down - entity-framework

What is a best way to implement ordering in collection?
Need to support operations like move up and move down.
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public int Priority { get; set; }
public List<Item> Items { get; set; }
}

This is a console applciation which demonstrates how to move up and down elements of a list.
I hope it helps you.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
public enum MoveDirection
{
Up,
Down
}
static class Program
{
static void Main(string[] args)
{
List<string> MyList = new List<string>
{
"Value 1", "Value 2", "Value 3"
};
DisplayList(MyList);
Console.WriteLine("----------------");
Move(MyList, 1, MoveDirection.Down);
DisplayList(MyList);
Console.WriteLine("----------------");
Move(MyList, 2, MoveDirection.Up);
DisplayList(MyList);
Console.ReadLine();
}
public static void Move(List<string> list, int iIndexToMove, MoveDirection direction)
{
if (direction == MoveDirection.Up && iIndexToMove > 0)
{
var old = list[iIndexToMove - 1];
list[iIndexToMove - 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
else if(direction == MoveDirection.Down && iIndexToMove < list.Count() - 1)
{
var old = list[iIndexToMove + 1];
list[iIndexToMove + 1] = list[iIndexToMove];
list[iIndexToMove] = old;
}
}
public static void DisplayList(List<string> list)
{
foreach (var item in list)
{
Console.WriteLine(item);
}
}
}
}

Related

Entity Framework saving in the write DBSet from abstract elements

net web app in witch database first and in my models they made the join tables as models. The thing that i want to do is that when i save ore edit a normal model i want to be able to update the relationships ass well. The problem is that i have a lot of repetitive code.For instance:
for (int i = 0; i < formationVM.Traits_.Length; i++)
{
_context.FormationTraits.Add(new FormationTrait(formationVM.Formation_, await _context.Traits.FirstOrDefaultAsync(q => q.Id == formationVM.Traits_[i])));
}
for (int i = 0; i < formationVM.Factions_.Length; i++)
{
_context.FactionFormations.Add(new FactionFormation(await _context.Factions.FirstOrDefaultAsync(q => q.Id == formationVM.Factions_[i]), formationVM.Formation_));
}
for (int i = 0; i < formationVM.Items_.Length; i++)
{
_context.ItemFormations.Add(new ItemFormation(await _context.Items.FirstOrDefaultAsync(q => q.Id == formationVM.Items_[i]), formationVM.Formation_));
}
So i want to make a single function that dose all the 3 repetitive task.
I thought of using abstraction in order to do this.
public interface IJointModel
{
public int IdLeft { get; set; }
public int IdRight { get; set; }
public IModel_ GetIdNavigationLeftModel();
public void SetIdNavigationLeftModel(IModel_ modelLeft);
public IModel_ GetIdNavigationRightModel();
public void SetIdNavigationRightModel(IModel_ modelRight);
public void saveYourself(TotalWarWanaBeContext context);
}
public interface IModel_
{
public int Id { get; set; }
}
public partial class Formation : IModel_
public partial class Trait :IModel_
public partial class FormationTrait : IJointModel{
public FormationTrait(Formation formation, Trait trait)
{
this.IdFormationNavigation = formation;
this.IdTraitNavigation = trait;
this.IdRight = trait.Id;
this.IdLeft = formation.Id;
}
[ForeignKey("IdFormationNavigation")]
[Column("IdFormation")]
public int IdLeft { get; set; }
[ForeignKey("IdTraitNavigation")]
[Column("IdTrait")]
public int IdRight { get; set; }
public virtual Formation IdFormationNavigation { get; set; }
public virtual Trait IdTraitNavigation { get; set; }
#region "Get_set_IJoinModel"
public IModel_ GetIdNavigationLeftModel()
{
return this.IdFormationNavigation;
}
public IModel_ GetIdNavigationRightModel()
{
return this.IdTraitNavigation;
}
public void SetIdNavigationLeftModel(IModel_ modelLeft)
{
this.IdFormationNavigation = (Formation)modelLeft;
}
public void SetIdNavigationRightModel(IModel_ modelRight)
{
this.IdTraitNavigation = (Trait)modelRight;
}
#endregion
public void saveYourself(TotalWarWanaBeContext context)
{
context.FormationTraits.Add(this);
}
}
The end goal is so that i can make the function
private void saveRelation(string jointableType/* ore something like this*/, IModel anyModel, int[] idLeftModels){
for(int i = 0; i < idLeftModels.Length; i++){
IJointModel jointModel = new IJointModel.TypeOf(jointTableType);
jointModel.setIdNavigationLeftModel = anyModel;
jointModel.setItNavigtionRightModel = _context.DbSetofTypeINeed.where(t => t.id = idLeftModels[i];
jointModel.SaveYourself();
}
How can I make the function saveRelation save in the database any Model that inherits from IJoinModel. Sorry if the title is miss representative but i didn't know how to phrase it

linq to entity on dbcontext.set<>

I have multiple databases, 1 common and n company db. I use code first with one migration for common and one for the companies db.
I have a base context this is inherit to 2 contexts (common, company). I try to use only the base context and remove the specified contexts, so far no problem.
My problem is following, if i try to use linq on context.Set<> then I get an InvalidOperationException "The entity type NOCompany is not part of the model for the current context".
using (NOContext db = new NOContext(connection)) {
var dbset = db.Set<NOCompany>()
.Where(company => (company.Deleted == null) || (company.Deleted == false));
foreach (var item in dbset) {
System.Diagnostics.Debug.WriteLine(item.Matchcode);
}
}
if I use this
using (NOContext db = new NOCommonContext(connection)) {
var dbset = db.Set<NOCompany>()
.Where(company => (company.Deleted == null) || (company.Deleted == false));
foreach (var item in dbset) {
System.Diagnostics.Debug.WriteLine(item.Matchcode);
}
}
then it works fine. Where is the problem?
Following excerpt from the classes
public class NOContext : DbContext, INOContext
{
public NOContext() { }
public NOContext(string connection) : base(connection) { }
#region - override DbContext -
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<EntityBase>()) {
DateTime currentDateTime = DateTime.Now;
var entity = entry.Entity;
if (entry.State == EntityState.Added) {
entity.CreateDate = currentDateTime;
entity.CreateId = NOEngine.SessionInfo.CurrentUserId;
} else if (entry.State == EntityState.Deleted) {
entry.State = EntityState.Modified;
entity.Deleted = true;
entity.DeletedDate = currentDateTime;
entity.DeletedId = NOEngine.SessionInfo.CurrentUserId;
}
entity.ModifiedDate = currentDateTime;
entity.ModifiedId = NOEngine.SessionInfo.CurrentUserId;
}
return base.SaveChanges();
}
#endregion
//database methods
}
Then I have 2 specified context
public class NOCommonContext : NOContext
{
public const string CommonCatalog = "NOCommonDb";
public NOCommonContext() { }
public NOCommonContext(string connection) : base(connection) { }
#region - DbSets -
public virtual DbSet<NOUser> Users { get; set; }
public virtual DbSet<NOCompany> Companies { get; set; }
public virtual DbSet<NOConfig> AppConfiguration { get; set; }
#endregion //DbSets
}
and
public partial class NOAppContext : NOContext
{
public NOAppContext() { }
public NOAppContext(string connection) : base(connection) { }
#region - DbSets -
public virtual DbSet<BPCard> BPCards { get; set; }
public virtual DbSet<BPContact> BPContacts { get; set; }
public virtual DbSet<HRCard> HRCards { get; set; }
#endregion //DbSets
}

Entity framework Generic query in Nongeneric Property

In Entity framework I have objectsets like
public partial class Building
{
public int BuildingID { get; set; }
public string BuildingName { get; set; }
}
public partial class Town
{
public int TownID { get; set; }
public string TownName { get; set; }
}
I want to create a generic query like
T.OrderBy(o=>o.Id).Skip(maxDispItem * (page - 1)).Take(maxDispItem).ToList();
T is generic class can be Building or Town but problem is BuildingId and TownId has different name.I don't want to change their name as Id and create interface IIdentity.
Maybe you could try something like this:
var query = (typeof(T) == typeof(Building) ?
context.Buildings.Select(b => new { Id = b.BuildingId, Name = b.BuildingName }) :
context.Towns.Select(t => new { Id = t.TownId, Name = b.TownName }))
.OrderBy(o => o.Id)...
Not tested but that's worth a test...
You can create generic method which find a field decorated with KeyAttribute, and then performs sorting by found key field. I have tested your model, works perfectly. Look at code snippet.
DbContext:
using System.Collections.Generic;
using System.Data.Entity;
namespace ConsoleApplication28.Entities
{
public class AppDbContext : DbContext
{
public AppDbContext()
{
Database.Connection.ConnectionString = #"Data Source=NOTEBOOK-PC;Initial Catalog=StackOverflowTest;Integrated Security=True";
Database.SetInitializer(new AppDbInitializer());
}
public DbSet<Town> Towns { get; set; }
public DbSet<Building> Buildings { get; set; }
}
public class AppDbInitializer : DropCreateDatabaseIfModelChanges<AppDbContext>
{
protected override void Seed(AppDbContext context)
{
context.Buildings.AddRange(new List<Building>
{
new Building {BuildingName = "Building1"},
new Building {BuildingName = "Building2"},
});
context.Towns.AddRange(new List<Town>
{
new Town {TownName = "Town1"},
new Town {TownName = "Town2"},
});
context.SaveChanges();
base.Seed(context);
}
}
}
Building
using System.ComponentModel.DataAnnotations;
namespace ConsoleApplication28.Entities
{
public class Building
{
[Key]
public int BuildingID { get; set; }
public string BuildingName { get; set; }
}
}
Town
using System.ComponentModel.DataAnnotations;
namespace ConsoleApplication28.Entities
{
public class Town
{
[Key]
public int TownID { get; set; }
public string TownName { get; set; }
}
}
Program
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using ConsoleApplication28.Entities;
using System.ComponentModel.DataAnnotations;
namespace ConsoleApplication28
{
class Program
{
static void Main(string[] args)
{
const int maxDispItem = 10;
const int page = 1;
var db = new AppDbContext();
var towns = db.Towns.OrderByKey().Skip(maxDispItem * (page - 1)).Take(maxDispItem).ToList();
var buildings = db.Buildings.OrderByKey().Skip(maxDispItem * (page - 1)).Take(maxDispItem).ToList();
}
}
public static class Extensions
{
/// <summary>
/// Sorts the elements of a sequence in ascending order according to a key specified using KeyAttribute
/// </summary>
public static IOrderedQueryable<T> OrderByKey<T>(this IQueryable<T> source, bool isAsc = true)
{
var type = typeof(T);
var keyProperty = type.GetProperties().Single(x => x.GetCustomAttributes(typeof(KeyAttribute)).Any());
return source.OrderBy(keyProperty.Name, isAsc);
}
#region COPIED FROM THERE http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property, bool isAsc)
{
return isAsc ? source.OrderBy(property) : source.OrderByDescending(property);
}
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "OrderByDescending");
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenBy");
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
{
return ApplyOrder<T>(source, property, "ThenByDescending");
}
static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
string[] props = property.Split('.');
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (string prop in props)
{
PropertyInfo pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
object result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}
#endregion
}
}

Entity Framework: Entity with composite key as PK/FK throws exception

On escalado, throws the exception. It throws with or wihtout Include.
static void Main(string[] args)
{
try
{
using (var context = new CKContext())
{
var servReprosWithIncludes = context.ServicioRepro
.Include(p => p.Categoria)
.ToList();
var escalado = context.EscaladoPrecio
//.Include(p => p.Servicio)
.ToList();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
InvalidOperationException: The value of a property that is part of an object's key does not match the corresponding property value stored in the ObjectContext. This can occur if properties that are part of the key return inconsistent or incorrect values or if DetectChanges is not called after changes are made to a property that is part of the key.
The mapping of EscaladoPrecio:
public class EscaladoPrecioMapping : EntityTypeConfiguration<EscaladoPrecio>
{
public EscaladoPrecioMapping()
{
base.HasKey(p => new { p.Desde, p.Hasta, p.ServicioReproId });
base.HasRequired(p => p.Servicio)
.WithMany()
.HasForeignKey(p => p.ServicioReproId);
base.ToTable("PreciosServicioReprografia");
}
}
The entity ServicioRepro is a part from TPT hierarchy. Looks like:
public class ServicioRepro : Producto
{
public bool IncluirPrecioClick { get; set; }
public bool IncluirPrecioPapel { get; set; }
public bool HayPapel { get; set; }
public bool HayImpresion { get; set; }
public bool PrecioPorVolumen { get; set; }
//public virtual ICollection<EscaladoPrecio> EscaladoPrecio { get; set; }
public virtual CategoriaServicioRepro Categoria { get; set; }
public virtual ServicioReproFacturacionType ServicioReproFacturacionType { get; set; }
}
On this entity you can't see the key, because the base entity Producto have it.
The entity EscaladoPrecio have 3 PK: desde, hasta and Servicio. Servicio is PK and FK.
The entity looks like (methods, overrides and members have been removed to reduce the code):
public class EscaladoPrecio : IComparable<EscaladoPrecio>, IComparable<int>, IComparable, IEntity
{
#region Declarations
private int _desde;
private int _hasta;
private double _precio;
private int _cada;
#endregion Declarations
#region Constructor
public EscaladoPrecio()
: this(1, 1, 0, 0)
{ }
public EscaladoPrecio(int desde, int hasta, double precio)
: this(desde, hasta, precio, 0)
{ }
public EscaladoPrecio(int desde, int hasta, double precio, int cada)
{
_desde = desde;
_hasta = hasta;
_precio = precio;
_cada = cada;
}
#endregion Constructor
#region Properties
public int Desde
{
get
{
return _desde;
}
set
{
_desde = value;
}
}
public int Hasta
{
get
{
return _hasta;
}
set
{
_hasta = value;
}
}
public double Precio
{
get
{
return _precio;
}
set
{
_precio = value;
}
}
public int Cada
{
get
{
return _cada;
}
set
{
_cada = value;
}
}
#endregion Properties
private int _ServicioReproId;
public int ServicioReproId
{
get
{
if (Servicio != null)
{
_ServicioReproId = Servicio.Id;
return Servicio.Id;
}
else
return 0;
}
set
{
_ServicioReproId = value;
}
}
public virtual ServicioRepro Servicio { get; set; }
}
Why throws the exception?
Why are you doing this:
public int ServicioReproId
{
get
{
if (Servicio != null)
{
_ServicioReproId = Servicio.Id;
return Servicio.Id;
}
else
return 0;
}
set
{
_ServicioReproId = value;
}
}
Your part of the key property ServicioReproId is returning 0 here potentially although it has been loaded (and stored in the context) with a value != 0 (probably). I think this part of the exception is refering to this problem: "This can occur if properties that are part of the key return inconsistent or incorrect values."
Better leave it an automatic property:
public int ServicioReproId { get; set; }
try to initialice his virtual property in the constructor of the class EscaladoPrecio()

implement N-Tier Entity Framework 4.0 with DTOs

I'm currently building a web based system and trying to implement N-Tier Entity Framework 4.0 with DTOs in a SOA Architecture. I am having a problem understanding how I should implement the Data Access Layer (DAL) , the Business Logic Layer (BLL) and the Presentation Layer.
Let’s suppose that I have a “useraccount” entity has the following :
Id
FirstName
LastName
AuditFields_InsertDate
AuditFields_UpdateDate
In the DAL I created a class “UserAccountsData.cs” as the following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OrderSystemDAL
{
public static class UserAccountsData
{
public static int Insert(string firstName, string lastName, DateTime insertDate)
{
using (OrderSystemEntities db = new OrderSystemEntities())
{
return Insert(db, firstName, lastName, insertDate);
}
}
public static int Insert(OrderSystemEntities db, string firstName,
string lastName, DateTime insertDate)
{
return db.UserAccounts_Insert(firstName, lastName, insertDate, insertDate).ElementAt(0).Value;
}
public static void Update(int id, string firstName, string lastName,
DateTime updateDate)
{
using (OrderSystemEntities db = new OrderSystemEntities())
{
Update(db, id, firstName, lastName, updateDate);
}
}
public static void Update(OrderSystemEntities db, int id, string firstName,
string lastName, DateTime updateDate)
{
db.UserAccounts_Update(id, firstName, lastName, updateDate);
}
public static void Delete(int id)
{
using (OrderSystemEntities db = new OrderSystemEntities())
{
Delete(db, id);
}
}
public static void Delete(OrderSystemEntities db, int id)
{
db.UserAccounts_Delete(id);
}
public static UserAccount SelectById(int id)
{
using (OrderSystemEntities db = new OrderSystemEntities())
{
return SelectById(db, id);
}
}
public static UserAccount SelectById(OrderSystemEntities db, int id)
{
return db.UserAccounts_SelectById(id).ElementAtOrDefault(0);
}
public static List<UserAccount> SelectAll()
{
using (OrderSystemEntities db = new OrderSystemEntities())
{
return SelectAll(db);
}
}
public static List<UserAccount> SelectAll(OrderSystemEntities db)
{
return db.UserAccounts_SelectAll().ToList();
}
}
}
And in the BLL I created a class “UserAccountEO.cs” as the following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using OrderSystemDAL;
namespace OrderSystemBLL
{
public class UserAccountEO
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime InsertDate { get; set; }
public DateTime UpdateDate { get; set; }
public string FullName
{
get
{
return LastName + ", " + FirstName;
}
}
public bool Save(ref ArrayList validationErrors)
{
ValidateSave(ref validationErrors);
if (validationErrors.Count == 0)
{
if (Id == 0)
{
Id = UserAccountsData.Insert(FirstName, LastName, DateTime.Now);
}
else
{
UserAccountsData.Update(Id, FirstName, LastName, DateTime.Now);
}
return true;
}
else
{
return false;
}
}
private void ValidateSave(ref ArrayList validationErrors)
{
if (FirstName.Trim() == "")
{
validationErrors.Add("The First Name is required.");
}
if (LastName.Trim() == "")
{
validationErrors.Add("The Last Name is required.");
}
}
public void Delete(ref ArrayList validationErrors)
{
ValidateDelete(ref validationErrors);
if (validationErrors.Count == 0)
{
UserAccountsData.Delete(Id);
}
}
private void ValidateDelete(ref ArrayList validationErrors)
{
//Check for referential integrity.
}
public bool Select(int id)
{
UserAccount userAccount = UserAccountsData.SelectById(id);
if (userAccount != null)
{
MapData(userAccount);
return true;
}
else
{
return false;
}
}
internal void MapData(UserAccount userAccount)
{
Id = userAccount.Id;
FirstName = userAccount.FristName;
LastName = userAccount.LastName;
InsertDate = userAccount.AuditFields_InsertDate;
UpdateDate = userAccount.AuditFields_UpdateDate;
}
public static List<UserAccountEO> SelectAll()
{
List<UserAccountEO> userAccounts = new List<UserAccountEO>();
List<UserAccount> userAccountDTOs = UserAccountsData.SelectAll();
foreach (UserAccount userAccountDTO in userAccountDTOs)
{
UserAccountEO userAccountEO = new UserAccountEO();
userAccountEO.MapData(userAccountDTO);
userAccounts.Add(userAccountEO);
}
return userAccounts;
}
}
}
And in the PL I created a webpage as the following :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using OrderSystemBLL;
using System.Collections;
namespace OrderSystemUI
{
public partial class Users : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadUserDropDownList();
}
}
private void LoadUserDropDownList()
{
ddlUsers.DataSource = UserAccountEO.SelectAll();
ddlUsers.DataTextField = "FullName";
ddlUsers.DataValueField = "Id";
ddlUsers.DataBind();
}
}
}
Is the above way the right way to Implement the DTOs pattern in n-tier Architecture using EF4 ???
I would appreciate your help
Thanks.
DTO's should only have properties, not methods like UserAccountEO. You should separate the DTO code from the logic that maps the entities to DTOs.
Everything else seems correct.
BTW: EntitiesToDTOs is a tool that generates DTOs from your Entity Framework EDMX file, it can help you a lot to save development time and effort.