Dapper Rainbow - How to specify table name in another schema - dapper

I am pretty new to Dapper Rainbow so I may be missing something obvious. Is it possible to specify the table name and if so how?
I have tried the following with no luck.
public class DashboardContext : Database<DashboardContext>
{
public DashboardContext()
{
this.DashboardResults = new Table<DashboardResult>(this, "Monitor.DashboardResult");
}
public Table<DashboardResult> DashboardResults { get; set; }
}

I had the same problem but it seems an error in the code. I´ve just commented the lines where is setting the constructor for tables (Database.cs) and it works.
internal void InitDatabase(DbConnection connection, int commandTimeout)
{
this.connection = connection;
//this.commandTimeout = commandTimeout;
//if (tableConstructor == null)
//{
// tableConstructor = CreateTableConstructorForTable();
//}
//tableConstructor(this as TDatabase);
}
I guess this is not the best solution...

You need to hack the rainbow source to get it to work.
Find the CreateTableConstructor method in the file of DataBase.cs.
Just add some code as following:
...
var setters = GetType().GetProperties()
.Where(p => p.GetValue(this, null) == null
&& p.PropertyType.IsGenericType
&& p.PropertyType.GetGenericTypeDefinition() == tableType)
.Select...

For anyone else stumpeling over this post like I did this is now fixed in Dapper.Rainbow version 0.1.3.
It is still in beta at this time (0.1.3-beta1) so if you want to use schema you can clone/fork the repository and run the build script. The binary output can then be used directly or packaged.
As for the table setup you need to define the table name with the name of the schema for for that particular table so for example looking at this example without schema
public class MyDatabase : Database<MyDatabase>
{
public Table<Order> Order{ get; set; }
public Table<Customer> Customer { get; set; }
public Table<Item> Item { get; set; }
}
Which works if you are only using dbo. but if you are for instance using say Product schema for Item you would have to define it using a constructor
public class MyDatabase : Database<MyDatabase>
{
public Table<Order> Order{ get; set; }
public Table<Customer> Customer{ get; set; }
public Table<Item> Item;
public MyDatabase()
{
Item = new Table<Item>(this, "Product.Item");
}
}
The rest should be as before
using (var connection = DbConnections.Create())
{
connection.Open();
var db = MyDatabase.Init((DbConnection)connection, commandTimeout: 2);
var insert = db.Customer.Insert(
// .
//..... your object
// .
);
var insertId = insert.Value;
}

Based on #Acorax answer, it wasn't enough for me, I needed to add brackets to the schema and table name to solve this.
So this solved me the schema problem:
public class MyDatabase : Database<MyDatabase>
{
public Table<Item> Items;
public HamenasDbSchema()
{
Items = new Table<User>(this, "[Schema].[Items]");
}
}

Related

Cannot Insert new Data in the Database in .NET Core API error Database operation

I am working on an API and when I started adding new data. I received this error. It was working when I manually add the ID every input but now I got this error and after adding some solutions from here its still not working.
Error:
Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: Database operation expected to affect 1 row(s) but actually affected 0 row(s).
Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
Code for insert:
public bool Insert(string UserName, SendInventoryModel sendInventoryModel)
{
using (DatabaseContext context = new DatabaseContext())
{
bool flag = false;
// Create new
InventoryEntity inventoryEntity = new InventoryEntity
{
UserName = sendInventoryModel.UserName,
Item = sendInventoryModel.Item ,
};
context.Table.Add(inventoryEntity);
context.SaveChanges();
// Check
var model = CheckUserNameID(UserName, sendInventoryModel.Item);
var data = context.Table.Find(model.Id);
if (null != data)
{
flag = true;
}
return flag;
}
}
SendInventoryModel:
public class SendSiteMailModel
{
[Required]
public string UserName { get; set; }
[Required]
public string Item{ get; set; }
}
InventoryController:
[HttpPost("{username}")]
[Authorize]
public JObject Post([Required] string UserName, [FromBody] SendInventoryModel sendInventoryModel)
{
ResponseModel x = new ResponseModel();
try
{
InventoryRepository InventoryRepository = new InventoryRepository();
bool isSuccess = InventoryRepository.Insert(UserName, sendInventoryModel);
}
catch (Exception error)
{
// if not successful
}
return Json(x);
}
I already added [DatabaseGenerated(DatabaseGeneratedOption.Identity)] in my InventoryEntity and InventoryModel.
InventoryEntity:
[Key]
DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
InventoryModel:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
I also added the below code in my DBContext.cs:
public virtual DbSet<OtherTableEntity> Table{ get; set; }
public virtual DbSet<InventoryEntity> Table{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<OtherTableEntity>();
modelBuilder.Entity<InventoryEntity>().Property(x => x.Id).ValueGeneratedOnAdd();
base.OnModelCreating(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
Add finally my table design: Inventory ID:
(Is Identity) = Yes
Identity Increment = 1
Identity Seed = 1
Note that there is no Primary Key in the Inventory table. And its an old table with existing data. The current database was migrated from membership to identity.
After all the things that I have added the context.SaveChanges(); in the insert method still does not work. Any ideas or suggestion on how to fix this problem?
Note: I've changed the table entity names and models per Asherguru suggestion since its kinda confusing and generic.
Are your TableEntity and Table in database same table names?
Why different names - TableEntity and Table?
Try to add [Table("YourTableNameInDatabase")] in TableEntity class. Then EF can find actual table in database and insert into this table.
[Table("YourTableNameInDatabase")]
public partial class TableEntity
{
public int Id { get; set; }
}
It would be less confusing if you show actual table names with some necessary screenshots.

EmployeeDataContext class not pulling data from Database

below is my code
I am trying to pull data from database using entityframework.
EmployeeDataContext class -
namespace _09032020_1.Models
{
public class EmployeeDataContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}
}
Employee model -
namespace _09032020_1.Models
{
[Table("TbleEmployee")]
public class Employee
{
public int employeeId { get; set; }
public string employeeName { get; set; }
public string employeeCity { get; set; }
public string employeeGender { get; set; }
public int departmentId { get; set; }
}
}
below are the table columns.
here is the controller code
namespace _09032020_1.Controllers
{
public class EmployeeController : Controller
{
public ActionResult Index()
{
EmployeeDataContext employeeDataContext = new EmployeeDataContext();
Employee employee = new Employee();
List<Employee> employees1 = new List<Employee>();
employees1 = employeeDataContext.Employees.ToList();
return View(employees1);
}
}
}
I am not getting data inside employeeDataContext
Please let me know if more info regarding config file requires.
Create the table w data. The first column is primary key and identity.
In an MVC project (you can use another type, also I am showing database first, and you can use another type, right click on the Models folder and add ADO.NET Entity Data Model named EmployeeDataContext. Choose EF Designer from database. New connection, and choose your db. Save connection as EmployeeDataContext and choose your table.
Put this in your code:
using (EmployeeDataContext context = new EmployeeDataContext())
{
var emps = context.Employees.ToList();
}
I got my answer,
I have written wrong table name as model attribute [Table("TbleEmployee")]
My table name is TblEmplyee. So it should be [Table("TblEmployee")]
As I changed this I abled to proceed forward.

Entity framework 6 not updating foreign key relation

Hello I have a strange issue here. I have a Project model that has a foreign key to the Company model. The thing is that when I attach my Project property in order to update it, then it updates all other primitive fields, except for the Company.
The Project model looks like this:
public class Project
{
[Key]
public int ID { get; set; }
[Index(IsUnique = true)]
public string Name { get; set; }
public virtual Company Company { get; set; }
public bool ExportProjectName { get; set; }
public DateTime CreatedAt { get; set; }
}
Then what I do, is I have a ProjectsViewModel, that gets all Projects from the Database. I wrap each of them then in a ProjectViewModel which exposes some fields of the Project and also has a saving method. I think the ProjectsViewModel implementation may not be that important so I'll paste only the two lines that populate the ProjectViewModels:
var projects = dbcontext.Projects.Include(x => x.Company).ToList().Select(x => new ProjectViewModel(x));
this.ListOfProjects = new ObservableCollection<ProjectViewModel>(projects);
Then I have the ProjectViewModel. Take a look at the SaveProject method:
public class ProjectViewModel : INotifyPropertyChanged
{
private Project _project;
public Project Project
{
get { return _project; }
set
{
_project = value;
NotifyPropertyChanged("Project");
}
}
public int ID
{
get { return Project.ID; }
set
{
Project.ID = value;
NotifyPropertyChanged("ID");
}
}
public string Name
{
get { return Project.Name; }
set
{
Project.Name = value;
NotifyPropertyChanged("Name");
}
}
public Company Company
{
get { return Project.Company; }
set
{
Project.Company = value;
NotifyPropertyChanged("Company");
}
}
public ProjectViewModel(Project project)
{
this.Project = project;
}
public void SaveProject()
{
using (DbContext dbcontext = new DbContext())
{
// At this state this.Project and this.Company exist in the database
dbcontext.Companies.Attach(this.Company);
dbcontext.Projects.Attach(this.Project);
dbcontext.Entry(this.Project).State = EntityState.Modified;
dbcontext.SaveChanges();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
}
And that's it. I have the SaveProject bound to a command, which I just trigger.
And then in the logs I can only see such a query:
Opened connection at 08/12/2018 17:47:21 +01:00
Started transaction at 08/12/2018 17:47:21 +01:00
UPDATE "public"."Projects" SET "Name"=#p_0,"ExportProjectName"=#p_1,"CreatedAt"=#p_2 WHERE "ID" = #p_3
So all properties are there, except for the Company. If that's important - I'm using PostgreSQL with NpgSql. I saw many question on SO in regards to the related object not being updated itself, but I couldn't find any question where the relation would be only broken. Hope somebody can help!
EDIT:
BTW the code below would work, but I do not want to assign all properties by myself and would want to avoid getting the object from the DB one more time. And I want to know, why the relation is not updated in the first case, as it doesn't make sense for me.
dbcontext.Companies.Attach(this.Company);
var p = dbcontext.Projects.Single(x => x.ID == this.ID);
p.Name = this.Name;
p.Company = this.Company;
dbcontext.SaveChanges();

Entity Framework auto assign FK to reference Entity during insertion?

Could you please explain for me Why and How EF auto assign FK to reference entity when i insert entities into Database? I got these simple Entities like this:
First one is Catalogue
public class Catalogue
{
public int CatalogueId { get; set; }
public string Name { get; set; }
public ICollection<Page> Pages { get; set; }
}
Second one is Page which reference to Catalogue.
public class Page
{
public int PageId { get; set; }
public string Name { get; set; }
public int CatalogueId { get; set; }
public Catalogue Catalogue { get; set; }
}
The relationship in this case is one to many. So in the code i am using this:
using (var context = new MyDbContext())
{
var catalogue = new Catalogue
{
Name = "catalogue 1"
};
var page = new Page
{
Name = "page 1",
CatalogueId = 0
};
context.Catalogues.Add(catalogue);
context.Pages.Add(page);
context.SaveChanges();
}
The MyDbContext is simple nothing special.
When i run this code i am expecting it will generate an error because CatalogueId = 0 is not valid, but it working fine,.
It is interesting me and hopefully someone can clarify that :).
Thanks in advance
This is how EF work under the hood. The context will go and execute the INSERT and generate the update for the FK value in the table. Later, will populate the tracked entity with the real key value.
You can experiment with unattached entities and will notice that no FK value is updated.

Storing search parameters

I'm currently building a website in .NET MVC 4, using Entity Framework to access SQL Server.
The website should have a complex search with multiple choices for the user, create a new search (free search), choose from the last 5 searches (history search), choose from stored search parameters.
What I'm having trouble with is the concept of saving the search parameters/sql string, because it's not sessional/cache based and should be stored somewhere (SQL Server / MongoDB / XML) I'm having the hard time in taking the most optimized path, if it's the SQL way then maybe create an entity that stores the search parameters as entities and afterward converting it into a SQL string for the search, or store it in XML and than serialize it with JSON.
Some fields of the search are not an exact db/entity match and requires summing/converting (like hours that would be calculated into certain time).
I'm more inclined to take out the best of Entity Framework abilities for the cause.
Would like to hear some expert thoughts if possible, Thank you.
Not sure if this is the "most optimized" path, but thought it seemed simple to implement:
//POCO class of item you want to search from database
public class SearchableItem
{
public string Name { get; set; }
public int Age { get; set; }
}
//MVC View Model for search page
public class SearchParamaters
{
public int? MinAge { get; set; }
public int? MaxAge { get; set; }
}
//Storable version for database
public class SavedSearchParameters : SearchParamters
{
public int SavedSearchParametersId { get; set; }
}
//Use SearchParameters from MVC, or SavedSearchParamaters from EF
public IQueryable<SearchableItem> DoSearch(SearchParamaters sp)
{
IQueryable<SearchableItem> query = db.SearchableItems;
if (sp.MinAge.HasValue) query = query.Where(x => x.Age >= sp.MinAge.Value);
if (sp.MaxAge.HasValue) query = query.Where(x => x.Age <= sp.MaxAge.Value);
return query;
}
You could also serialize the SearchParameters class as XML/JSON and save it wherever, then deserialize it and pass it to the DoSearch method as normal, then you wouldn't have to change the DB schema every time you wanted to add search parameters
EDIT: Full example using serialization
\Domain\Person.cs
namespace YourApp.Domain
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
\Domain\SavedPersonSearch.cs
namespace YourApp.Domain
{
//Entity object with serialized PersonSearchParameters
public class SavedPersonSearch
{
public int Id { get; set; }
public string Name { get; set; }
public string Parameters { get; set; }
}
}
\Models\PersonSearchParameters.cs
namespace YourApp.Models
{
//MVC View Model for search page
public class PersonSearchParameters
{
public int? MinAge { get; set; }
public int? MaxAge { get; set; }
}
}
\Helpers\SearchProvider.cs
using YourApp.Domain;
using YourApp.Models;
namespace YourApp.Helpers
{
public class SearchProvider
{
private YourAppDbContext _context;
public SearchProvider(YourAppDbContext context)
{
//This example uses the DbContext directly
//but you could use a Unit of Work, repository, or whatever
//design pattern you've decided on
_context = context;
}
public IQueryable<Person> SearchPersons(int savedPersonSearchId)
{
var savedSearch = _context.SavedPersonSearches.Find(savedPersonSearchId);
//deserialize (example assumes Newtonsoft.Json)
var searchParams = JsonConvert.Deserialize<PersonSearchParameters>(savedSearch.Parameters);
return SearchPersons(searchParams);
}
public IQueryable<Person> SearchPersons(PersonSearchParameters sp)
{
IQueryable<Person> query = _context.Persons;
if (sp.MinAge.HasValue) query = query.Where(x => x.Age >= sp.MinAge.Value);
if (sp.MaxAge.HasValue) query = query.Where(x => x.Age <= sp.MaxAge.Value);
return query;
}
public void SavePersonSearch(PersonSearchParameters sp, string name)
{
var savedSearch = new SavedPersonSearch { Name = name };
savedSearch.Parameters = JsonConvert.Serialize(sp);
_context.SavedPersonSearches.Add(savedSearch);
_context.SaveChanges();
}
}
}
\Controllers\PersonController.cs
namespace YourApp.Controllers
{
public class PersonsController : Controller
{
private SearchProvider _provider;
private YourAppDbContext _context;
public PersonsController()
{
_context = new YourAppDbContext();
_provider = new SearchProvider(_context);
}
//Manual search using form
// GET: /Persons/Search?minAge=25&maxAge=30
public ActionResult Search(PersonSearchParameters sp)
{
var results = _provider.SearchPersons(sp);
return View("SearchResults", results);
}
//Saved search
// GET: /Persons/SavedSearch/1
public ActionResult SavedSearch(int id)
{
var results = _provider.SearchPersons(id);
return View("SearchResults", results);
}
[HttpPost]
public ActionResult SaveMySearch(PersonSearchParameters sp, name)
{
_provider.SavePersonSearch(sp, name);
//Show success
return View();
}
}
}
conver your parameters to Base64 string. It would help you to create any hard queries for example, http://www.jobs24.co.uk/SearchResults.aspx?query=djAuMXxQUzoxMHx2MC4x&params=cXVlcnlmaWx0ZXI6 decode base64 use this service http://www.opinionatedgeek.com/DotNet/Tools/Base64Decode/default.aspx
you can also take a look on http://aws.amazon.com/cloudsearch/ it may be give you an idea about worh with parameters in your project
Something like this could work:
Store the search parameters in json/xml and persist in DB table.
1. When you want to edit the search parameters (if you even allow this), use the json/xml to pre-fill the selected parameters so user can edit criteria.
2. When user wants to run search, take parameters from json and create/run the query.
OR
Store the search parameters in json/xml and persist in DB table and also create the sql query and store the sql string (after validating parameters)
1. When you want to edit the search parameters (if you even allow this), use the json/xml to pre-fill the selected parameters so user can edit criteria.
2. When user wants to run search, simply take the saved query string and execute it.

Resources