I try to moq my DbContext like in memory db. I use PostgreSql in my app, so I have entities with jsonb properties. For example:
[Table("examples")]
public class Example
{
/// <summary>
/// id (autogenerated by DB)
/// </summary>
[Column("id", TypeName = "bigserial")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
/// <inheritdoc/>
[Column("layout_config", TypeName = "jsonb")]
[Required]
public LayoutConfigDto LayoutConfig { get; set; }
}
[Keyless]
public class LayoutConfigDto
{
/// <summary>
/// Координата X расположения виджета
/// </summary>
public byte X { get; set; }
/// <summary>
/// Координата Y расположения виджета
/// </summary>
public byte Y { get; set; }
}
so LayoutConfigDto just a model for JSON, that doesn't need a table. And doesn't need any relation or configuration for table.
Then I create Test class:
[TestFixture]
public class ExampleServiceTests
{
private IExampleService _exampleService;
[SetUp]
public void Setup()
{
DbContextOptions<ExampleDbContext> options = new DbContextOptionsBuilder<ExampleDbContext>()
.UseInMemoryDatabase(databaseName: "InMemoryExampleDatabase")
.Options;
ExampleDbContext dbContext = new(options);
new FakeDatabaseDataGenerator().Generate(dbContext);
Mock<ILogger<ExampleService>> mock = new();
_exampleService = new ExampleService(dbContext, mock.Object);
}
[Test]
[TestCase(0)]
[TestCase(3)]
public async Task GetExampleTest(long id)
{
ExampleModel example = await _exampleService.GetExample(id);
if (id <= 0)
{
Assert.AreEqual(example, null);
return;
}
Assert.AreNotEqual(null, example);
}
}
When I run GetExampleTest it fails on Exceptions like:
System.InvalidOperationException : Unable to determine the relationship represented by navigation 'UserWidgetModel.LayoutConfig' of type 'LayoutConfigDto'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I can't use [NotMapped] attribute on LayoutConfig field, because I need to get it from DB and with pgsql driver all works and serializes. But with in memory db it fails. How can I change my Test to make it works? Is there any other options to mock db context?
The error it returns is pretty clear; it tells you what you need to do. If you can't use the [NotMapped] attribute, you need to configure a relationship for the fields it needs
Related
Is there a way to specify example requests for swagger? Maybe even multiple ones?
The Try it out button shows only generic values like:
{
"firstName": "string",
"lastName": "string"
}
for
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
It becomes very difficult to use with large objects when you have to edit all the values first. I know I could use Postman, and I do too, but being able to create multiple good looking and useful examples with swagger would be very nice.
In .Net5 you can add a SchemaFilter to Swagger in the Startup.cs
public override void ConfigureServices(IServiceCollection services)
{
services.AddSwaggerGen(c =>
{
c.SchemaFilter<ExampleSchemaFilter>();
});
}
In the ExampleSchemaFilter.cs you simply define an OpenApiObject for your specific class:
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
public class ExampleSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type == typeof(User))
{
schema.Example = new OpenApiObject()
{
["firstName"] = new OpenApiString("John"),
["lastName"] = new OpenApiString("Doe"),
};
}
}
}
With ASP.NET Core 3.1, Swagger OAS 3 and Swashbuckle.AspNetCore 5.4.1, the following model class + XML comments works for me:-
/// <summary>
/// A user.
/// </summary>
public class User
{
/// <summary>
/// The user's first name.
/// </summary>
/// <example>Jane</example>
public string FirstName { get; set; }
/// <summary>
/// The user's last name.
/// </summary>
/// <example>Austin</example>
public string LastName { get; set; }
}
Now when I click "Try it Out" (for a POST operation that takes a User model in the message body), I get the defaults:-
{
"firstName": "Jane",
"lastName": "Austin"
}
I'm new to Xamarin forms and am up to the point where I now want to be persisting data entered by the user to an Sqlite db. Thankfully, there all plenty of examples to get you started, but thats as far as the help goes... I'm trying to implement a relationship between two entities 'Session' and 'HandHistory'.
A Session can have multiple HandHistories - immediately I saw that some sort of foreign key would be needed here to link these tables/entities together. I read in multiple articles and stack overflow questions that the standard 'sqlite-net-pcl' (by Frank A.Krueger) package offers nothing in terms of foreign keys, and that in order to acquire the functionality I needed to use the SQLiteNetExtensions library. I referred to this article for help:
https://bitbucket.org/twincoders/sqlite-net-extensions/overview
My entities look like this:
Session:
using SQLite;
using SQLiteNetExtensions.Attributes;
namespace PokerSession.Models
{
[Table("Session")]
[AddINotifyPropertyChangedInterface]
public class Session
{
public Session(bool newSession)
{
if (newSession)
{
CurrentlyActive = true;
//HandHistories = new ObservableCollection<HandHistory>();
}
}
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public SessionType SessionType { get; set; } = SessionType.Tournament;
public string Location { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
public string GeneralNotes { get; set; }
public int MoneyIn { get; set; }
public int MoneyOut { get; set; }
public int ProfitLoss
{
get
{
var p = MoneyOut - MoneyIn;
if (p < 0)
return 0;
return p;
}
}
/// <summary>
/// If the session has not been completed, set this to true
/// </summary>
public bool CurrentlyActive { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public ObservableCollection<HandHistory> HandHistories { get; set; }
}
}
HandHistory:
using SQLite;
using SQLiteNetExtensions.Attributes;
namespace PokerSession.HandHistories
{
[Table("HandHistory")]
[AddINotifyPropertyChangedInterface]
public class HandHistory
{
public HandHistory()
{
}
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(Session))]
public int SessionId { get; set; }
[ManyToOne]
public Session Session { get; set; }
}
}
I also followed this article for the platform specific implementations for obtaining the SQLiteConnection for the local db:
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/
The error I'm getting:
'SQLiteConnection' does not contain a definition for 'UpdateWithChildren' and the best extension method overload 'WriteOperations.UpdateWithChildren(SQLiteConnection, object)' requires a receiver of type 'SQLiteConnection' PokerSession.Android, PokerSession.iOS C:\Poker Notes Live\PokerSession\PokerSession\PokerSession\Services\DataService.cs 46 Active
private SQLiteConnection _database;
public DataService()
{
_database = DependencyService.Get<ISqLite>().GetConnection();
_database.GetTableInfo("HandHistory");
_database.CreateTable<Session>();
_database.CreateTable<HandHistory>();
var session = new Session(false)
{
Location = "Test Location",
Date = new DateTime(2017, 08, 26),
MoneyIn = 35,
MoneyOut = 0,
SessionType = SessionType.Tournament,
GeneralNotes = "blah blah"
};
var hh = new HandHistory();
_database.Insert(session);
_database.Insert(hh);
session.HandHistories = new ObservableCollection<HandHistory> {hh};
_database.UpdateWithChildren(session);
}
So basically it's not allowing me to use the SQLite Extension methods with my SQLiteConnection object (_database) which is confusing as this is the whole point behind the Extension methods? Surely they're made to work with the SQLiteConnection object?? I've also noticed through my playing around that there seems to be two different types of SQLiteConnection... The one I'm currently using is in the 'SQLite' namespace, and another one in the SQLite.Net namespace. I have checked the one in the SQLite.Net namespace and it does seem to like the Extension methods but it requires me to change my platform specific implementation for obtaining the SQLiteConnection, but it would fail at runtime (complaining about my Session entity not having a PK??).
Quite a long winded question I know but it's better to provide more information than not enough, and I'm sure there must be others experiencing similar problems so please comment and offer any help possible, thank you.
A default MVC 5 App comes with this piece of code in IdentityModels.cs - this piece of code is for all the ASP.NET Identity operations for the default templates:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}
If I scaffold a new controller using views with Entity Framework and create a "New data context..." in the dialog, I get this generated for me:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace WebApplication1.Models
{
public class AllTheOtherStuffDbContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, please use data migrations.
// For more information refer to the documentation:
// http://msdn.microsoft.com/en-us/data/jj591621.aspx
public AllTheOtherStuffDbContext() : base("name=AllTheOtherStuffDbContext")
{
}
public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; }
}
}
If I scaffold another controller + view using EF, say for instance for an Animal model, this new line would get autogenerated right under public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; } - like this:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace WebApplication1.Models
{
public class AllTheOtherStuffDbContext : DbContext
{
// You can add custom code to this file. Changes will not be overwritten.
//
// If you want Entity Framework to drop and regenerate your database
// automatically whenever you change your model schema, please use data migrations.
// For more information refer to the documentation:
// http://msdn.microsoft.com/en-us/data/jj591621.aspx
public AllTheOtherStuffDbContext() : base("name=AllTheOtherStuffDbContext")
{
}
public System.Data.Entity.DbSet<WebApplication1.Models.Movie> Movies { get; set; }
public System.Data.Entity.DbSet<WebApplication1.Models.Animal> Animals { get; set; }
}
}
ApplicationDbContext (for all the ASP.NET Identity stuff) inherits from IdentityDbContext which in turn inherits from DbContext.
AllOtherStuffDbContext (for my own stuff) inherits from DbContext.
So my question is:
Which of these two (ApplicationDbContext and AllOtherStuffDbContext) should I use for all my other own models? Or should I just use the default autogenerated ApplicationDbContext since it shouldn't be a problem using it since it derives from the base class DbContext, or will there be some overhead? You should use only one DbContext object in your app for all your models (I've read this somewhere) so I should not even consider using both ApplicationDbContext and AllOtherStuffDbContext in a single app? Or what is best practice in MVC 5 with ASP.NET Identity?
I would use a single Context class inheriting from IdentityDbContext.
This way you can have the context be aware of any relations between your classes and the IdentityUser and Roles of the IdentityDbContext.
There is very little overhead in the IdentityDbContext, it is basically a regular DbContext with two DbSets. One for the users and one for the roles.
There is a lot of confusion about IdentityDbContext, a quick search in Stackoverflow and you'll find these questions:
"
Why is Asp.Net Identity IdentityDbContext a Black-Box?
How can I change the table names when using Visual Studio 2013 AspNet Identity?
Merge MyDbContext with IdentityDbContext"
To answer to all of these questions we need to understand that IdentityDbContext is just a class inherited from DbContext.
Let's take a look at IdentityDbContext source:
/// <summary>
/// Base class for the Entity Framework database context used for identity.
/// </summary>
/// <typeparam name="TUser">The type of user objects.</typeparam>
/// <typeparam name="TRole">The type of role objects.</typeparam>
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
/// <typeparam name="TUserClaim">The type of the user claim object.</typeparam>
/// <typeparam name="TUserRole">The type of the user role object.</typeparam>
/// <typeparam name="TUserLogin">The type of the user login object.</typeparam>
/// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam>
/// <typeparam name="TUserToken">The type of the user token object.</typeparam>
public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : DbContext
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityDbContext"/>.
/// </summary>
/// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
public IdentityDbContext(DbContextOptions options) : base(options)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="IdentityDbContext" /> class.
/// </summary>
protected IdentityDbContext()
{ }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of Users.
/// </summary>
public DbSet<TUser> Users { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User claims.
/// </summary>
public DbSet<TUserClaim> UserClaims { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User logins.
/// </summary>
public DbSet<TUserLogin> UserLogins { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
/// </summary>
public DbSet<TUserRole> UserRoles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens.
/// </summary>
public DbSet<TUserToken> UserTokens { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
/// </summary>
public DbSet<TRole> Roles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
/// </summary>
public DbSet<TRoleClaim> RoleClaims { get; set; }
/// <summary>
/// Configures the schema needed for the identity framework.
/// </summary>
/// <param name="builder">
/// The builder being used to construct the model for this context.
/// </param>
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<TUser>(b =>
{
b.HasKey(u => u.Id);
b.HasIndex(u => u.NormalizedUserName).HasName("UserNameIndex").IsUnique();
b.HasIndex(u => u.NormalizedEmail).HasName("EmailIndex");
b.ToTable("AspNetUsers");
b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();
b.Property(u => u.UserName).HasMaxLength(256);
b.Property(u => u.NormalizedUserName).HasMaxLength(256);
b.Property(u => u.Email).HasMaxLength(256);
b.Property(u => u.NormalizedEmail).HasMaxLength(256);
b.HasMany(u => u.Claims).WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
b.HasMany(u => u.Logins).WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
b.HasMany(u => u.Roles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
});
builder.Entity<TRole>(b =>
{
b.HasKey(r => r.Id);
b.HasIndex(r => r.NormalizedName).HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken();
b.Property(u => u.Name).HasMaxLength(256);
b.Property(u => u.NormalizedName).HasMaxLength(256);
b.HasMany(r => r.Users).WithOne().HasForeignKey(ur => ur.RoleId).IsRequired();
b.HasMany(r => r.Claims).WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
});
builder.Entity<TUserClaim>(b =>
{
b.HasKey(uc => uc.Id);
b.ToTable("AspNetUserClaims");
});
builder.Entity<TRoleClaim>(b =>
{
b.HasKey(rc => rc.Id);
b.ToTable("AspNetRoleClaims");
});
builder.Entity<TUserRole>(b =>
{
b.HasKey(r => new { r.UserId, r.RoleId });
b.ToTable("AspNetUserRoles");
});
builder.Entity<TUserLogin>(b =>
{
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
b.ToTable("AspNetUserLogins");
});
builder.Entity<TUserToken>(b =>
{
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
b.ToTable("AspNetUserTokens");
});
}
}
Based on the source code if we want to merge IdentityDbContext with our DbContext we have two options:
**First Option:**
Create a DbContext which inherits from IdentityDbContext and have access to the classes.
public class ApplicationDbContext
: IdentityDbContext
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
static ApplicationDbContext()
{
Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
// Add additional items here as needed
}
Extra Notes:
We can also change asp.net Identity default table names with the following solution:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(): base("DefaultConnection")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("user");
modelBuilder.Entity<ApplicationUser>().ToTable("user");
modelBuilder.Entity<IdentityRole>().ToTable("role");
modelBuilder.Entity<IdentityUserRole>().ToTable("userrole");
modelBuilder.Entity<IdentityUserClaim>().ToTable("userclaim");
modelBuilder.Entity<IdentityUserLogin>().ToTable("userlogin");
}
}
Furthermore we can extend each class and add any property to classes like 'IdentityUser', 'IdentityRole', ...
public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole()
{
this.Id = Guid.NewGuid().ToString();
}
public ApplicationRole(string name)
: this()
{
this.Name = name;
}
// Add any custom Role properties/code here
}
// Must be expressed in terms of our custom types:
public class ApplicationDbContext
: IdentityDbContext<ApplicationUser, ApplicationRole,
string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
static ApplicationDbContext()
{
Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
// Add additional items here as needed
}
To save time we can use AspNet Identity 2.0 Extensible Project Template to extend all the classes.
Second Option:(Not recommended)
We actually don't have to inherit from IdentityDbContext if we write all the code ourselves.
So basically we can just inherit from DbContext and implement our customized version of "OnModelCreating(ModelBuilder builder)" from the IdentityDbContext source code
This is a late entry for folks, but below is my implementation. You will also notice I stubbed-out the ability to change the the KEYs default type: the details about which can be found in the following articles:
Extending Identity Models and Using Integer Keys Instead of Strings
Change Primary Key for Users in ASP.NET Identity
NOTES:
It should be noted that you cannot use Guid's for your keys. This is because under the hood they are a Struct, and as such, have no unboxing which would allow their conversion from a generic <TKey> parameter.
THE CLASSES LOOK LIKE:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, CustomRole, string, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
#region <Constructors>
public ApplicationDbContext() : base(Settings.ConnectionString.Database.AdministrativeAccess)
{
}
#endregion
#region <Properties>
//public DbSet<Case> Case { get; set; }
#endregion
#region <Methods>
#region
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//modelBuilder.Configurations.Add(new ResourceConfiguration());
//modelBuilder.Configurations.Add(new OperationsToRolesConfiguration());
}
#endregion
#region
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
#endregion
#endregion
}
public class ApplicationUser : IdentityUser<string, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
#region <Constructors>
public ApplicationUser()
{
Init();
}
#endregion
#region <Properties>
[Required]
[StringLength(250)]
public string FirstName { get; set; }
[Required]
[StringLength(250)]
public string LastName { get; set; }
#endregion
#region <Methods>
#region private
private void Init()
{
Id = Guid.Empty.ToString();
}
#endregion
#region public
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
#endregion
#endregion
}
public class CustomUserStore : UserStore<ApplicationUser, CustomRole, string, CustomUserLogin, CustomUserRole, CustomUserClaim>
{
#region <Constructors>
public CustomUserStore(ApplicationDbContext context) : base(context)
{
}
#endregion
}
public class CustomUserRole : IdentityUserRole<string>
{
}
public class CustomUserLogin : IdentityUserLogin<string>
{
}
public class CustomUserClaim : IdentityUserClaim<string>
{
}
public class CustomRoleStore : RoleStore<CustomRole, string, CustomUserRole>
{
#region <Constructors>
public CustomRoleStore(ApplicationDbContext context) : base(context)
{
}
#endregion
}
public class CustomRole : IdentityRole<string, CustomUserRole>
{
#region <Constructors>
public CustomRole() { }
public CustomRole(string name)
{
Name = name;
}
#endregion
}
If you drill down through the abstractions of the IdentityDbContext you'll find that it looks just like your derived DbContext. The easiest route is Olav's answer, but if you want more control over what's getting created and a little less dependency on the Identity packages have a look at my question and answer here. There's a code example if you follow the link, but in summary you just add the required DbSets to your own DbContext subclass.
I have a Generic Repository class using code first to perform data operations.
public class GenericRepository<T> where T : class
{
public DbContext _context = new DbContext("name=con");
private DbSet<T> _dbset;
public DbSet<T> Dbset
{
set { _dbset = value; }
get
{
_dbset = _context.Set<T>();
return _dbset;
}
}
public IQueryable<T> GetAll()
{
return Dbset;
}
}
I have an entity class Teacher, which maps to an existing table "Teacher" in my database, with exactly the same fields.
public class Teacher
{
public Teacher()
{
//
// TODO: Add constructor logic here
//
}
public int TeacherID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
I have the following code below which binds data from Teacher to a repeater control.
GenericRepository<Teacher> studentrepository = new GenericRepository<Teacher>();
rptSchoolData.DataSource = studentrepository.GetAll().ToList();
rptSchoolData.DataBind();
But I get an exception exception "The entity type Teacher is not part of the model in the current context". Do I have to do any additional work when using an existing database for code first?
You must create a context class that derives from DbContext. The class should have properties of type DbSet<T> which will give EF enough information to create and communicate with a database with default naming and association conventions. It will use properties like Student.Teacher (if any) to infer foreign key associations:
public class MyContext: DbContext
{
public DbSet<Teacher> Teachers { get; set; }
public DbSet<Student> Students { get; set; }
...
}
If the defaults are not what you want, or when you've got an existing database that you want to match with the names and associations in your model you can do two (or three) things:
Override OnModelCreating to configure the mappings manually. Like when the tables in the database have those ugly prefixes (to remind people that they see a table when they see a table):
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Teacher>()
.Map(e => e.ToTable("tblTeacher"));
...
}
(Less favorable) Use data annotations to do the same.
Turn it around and use Entity Framework Powertools to reverse-engineer a database into a class model including fluent mappings and a DbContext-derived context. Maybe easier to modify an existing model than to start from scratch.
I am using NewtonSoft.JSON. When running
JsonConvert.SerializeObject(myObject)
it is adding an $id value to my JSON - like this:
"$id": "1",
"BookingId": 0,
"CompanyId": 0,
"IsCashBooking": false,
"PaymentMethod": 0,
"IsReferral": false,
"IsReferralPercent": false,
"ReferralPaymentType": 0,
"ReferralDues": 0,
"PassengerId": 0,
"DepartmentID": 0,
"CostCenterID": 0,
"DeadMiles": 0
Can we remove this $id with some JsonSerializerSettings or by any other method?
If yes - then how...
I added this code to my WebApiConfig register method and I got rid of all $id in JSON.
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
If for some reason you're using a custom ContractResolver, take a look at this other stack overflow;
Json.Net adding $id to EF objects despite setting PreserveReferencesHandling to "None"
To remove the $id in JSON for my web API. I included [JsonObject(IsReference = false)] for my class objects and [JsonProperty(IsReference = false)] for my properties that are of object types. In my case the RespObj property is generic Type T and could take any object type I pass to it including collections so I had to use [JsonProperty(IsReference = false)] to get rid of the $id in the serialized JSON string.
I did not change my WebApiConfig because I was using the MVC help page for WEB API and it required me to have this configuration in my webApiconfig:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
The class object
[DataContract(IsReference = true)]
[JsonObject(IsReference = false)]
public class QMResponse<T> where T : new()
{
public QMResponse()
{
}
/// <summary>
/// The response code
/// </summary>
public string RespCode { get; set; }
/// <summary>
/// The response message
/// </summary>
public string RespMxg { get; set; }
/// <summary>
/// The exception message
/// </summary>
public string exception { get; set; }
/// <summary>
/// The object type returned
/// </summary>
[JsonProperty(IsReference = false)]
public T RespObj { get; set; }
/// <summary>
/// No of records returned
/// </summary>
public long RecordCount { get; set; }
/// <summary>
/// The Session Object
/// </summary>
public string session_id { get; set; }
}
In case 'id' is a property of your class then apply [JsonIgnore] attribute on it.
Otherwise probably here is the answer for your question:
http://james.newtonking.com/json/help/index.html?topic=html/PreserveObjectReferences.htm
You can keep the basic configuration:
Newtonsoft.Json.PreserveReferencesHandling.All;
I used this code format for my methods
public JsonResult<T> Get()
{
return Json(result);
}
It works fine for me.
The custom ContractResolver setting overrides the PreserveReferencesHandling setting.
In your implementation of DefaultContractResolver/IContractResolver, add this;
public override JsonContract ResolveContract(Type type) {
var contract = base.ResolveContract(type);
contract.IsReference = false;
return contract;
}
This behaves similarly to the PreserveReferencesHandling.None setting without a custom ContractResolver