I have the following mapping using code-first:
{
/// <summary>
/// Entity Framework Dc.Dc database table object representation
/// </summary>
[Table("DCDC", Schema = "MZMESDB")]
public class EfDcDc
{
/// <summary>
/// Element ID
/// </summary>
[Column("ID")]
public int Id { get; set; }
/// <summary>
/// Name of DC
/// </summary>
[Column("NAME")]
public string Name { get; set; }
/// <summary>
/// DC Description
/// </summary>
[Column("DESCRIPTION")]
public string Description { get; set; }
/// <summary>
/// Foreign Key
/// </summary>
public virtual EfSystemDataModule Module { get; set; }
/// <summary>
/// Name of module
/// </summary>
[Column("ENABLED")]
public string Enabled { get; set; }
}
}
and
{
/// <summary>
/// Entity Framework SystemData.Module database table object representation
/// </summary>
[Table("SYSTEMDATAMODULE", Schema = "MZMESDB")]
public class EfSystemDataModule
{
/// <summary>
/// Element ID
/// </summary>
[Column("ID")]
public int Id { get; set; }
/// <summary>
/// Name of module
/// </summary>
[Column("NAME")]
public string Name { get; set; }
/// <summary>
/// If the module is installed. Char because Oracle does not support boolean
/// </summary>
[Column("INSTALLED")]
public char Installed { get; set; }
/// <summary>
/// If the module is enabled. Char because Oracle does not support boolean
/// </summary>
[Column("ENABLED")]
public char Enabled { get; set; }
}
}
Oracle tables has a foreign key:
CREATE TABLE "MZMESDB"."DCDC" (
"ID" INTEGER NOT NULL ,
"NAME" VARCHAR2(64) NOT NULL ,
"DESCRIPTION" VARCHAR(256),
"MODULE_ID" INTEGER NOT NULL,
"MODULE_NAME" VARCHAR(64) NOT NULL,
"ENABLED" CHAR NOT NULL,
PRIMARY KEY ("ID") VALIDATE,
FOREIGN KEY (MODULE_ID, MODULE_NAME) REFERENCES SYSTEMDATAMODULE(ID, NAME)
No problems at compilation, but at rutime when I issue:
MzDbContext dbContext = new MzDbContext();
EfDcDc configuredDC = new EfDcDc();
try
{
configuredDC = dbContext.efDcDc.FirstOrDefault(item => item.Name == "COMMON_NAME");
}
catch (Exception e)
{
Debug.WriteLine("Error reading from database. Message: " + e.Message.ToString());
return false;
}
I get the following error from Oracle EF driver:
ORA-00904: \"Extent1\"."\"Module_Id\":Invalid identifier.
I just wanna check if the DcDc element exists in the database to later take its data for processing. what am I doing wrong ?
Rds
This is usually from an invalid column name. In Oracle, everything is in upper case for the column names. Where is the mixed case Module_Id coming from? I only see the ID used in your code.
The problem is related to EF internal mechanism that is not uppercasing some internal names...
So, Module_Id does not exist in Oracle, as the table fields are MODEL_ID. I´m still working around on this...
Related
I'm using c# .NET Framework 4.7.2, MySqlData and MySqlDataEntityFramework 8.0.22.0. This is my DbContext derived class:
/// <summary>
/// This is the class that maps the database table to the project's classes.
/// </summary>
[DbConfigurationType(typeof(MySqlEFConfiguration))]
class DatabaseContext : DbContext
{
/// <summary>
/// Session table.
/// </summary>
public DbSet<Session_table> Sessions { get; set; }
/// <summary>
/// Measure table.
/// </summary>
public DbSet<Measure_table> Measures { get; set; }
public DatabaseContext() : base()
{
//this.Configuration.LazyLoadingEnabled = false;
}
public DatabaseContext(System.Data.Common.DbConnection existingConnection, bool contextOwnConnection)
: base(existingConnection, contextOwnConnection)
{
}
///// <summary>
///// Measure Table.
///// </summary>
//public DbSet<Measure_table> Measures { get; set; }
/// <summary>
/// Override used to map class to database table.
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
#region Session Table
// session_id is the primary key
modelBuilder.Entity<Session_table>().HasKey(e => e.session_id);
// Specify the name of the table
modelBuilder.Entity<Session_table>().ToTable("session");
// Prevent MySql Server to auto-generate the value for primary key
modelBuilder.Entity<Session_table>().Property(a => a.session_id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
// session_id: Specify name and mark as required
modelBuilder.Entity<Session_table>().Property(e => e.session_id).HasColumnName("session_id");
modelBuilder.Entity<Session_table>().Property(e => e.session_id).IsRequired();
// time_start: Specify name and mark as required
modelBuilder.Entity<Session_table>().Property(e => e.sessionTimeStart).HasColumnName("time_start");
modelBuilder.Entity<Session_table>().Property(e => e.sessionTimeStart).IsRequired();
// Time end: Specify name and mark as required
modelBuilder.Entity<Session_table>().Property(e => e.sessionTimeEnd).HasColumnName("time_end");
modelBuilder.Entity<Session_table>().Property(e => e.sessionTimeEnd).IsRequired();
// Description: Specify name and max length
modelBuilder.Entity<Session_table>().Property(e => e.description).HasColumnName("description");
modelBuilder.Entity<Session_table>().Property(e => e.description).HasMaxLength(255);
#endregion Session Table
#region Measure Table
var measureTable = modelBuilder.Entity<Measure_table>();
measureTable.HasKey(e => e.measure_id);
measureTable.HasIndex(a => a.session_id);
measureTable.HasRequired<Session_table>(e => e.session).WithMany().HasForeignKey(e => e.session_id);
measureTable.ToTable("measure");
// Measure Id
measureTable.Property(e => e.measure_id).HasColumnName("measure_id");
measureTable.Property(e => e.measure_id).IsRequired();
// Session Time
measureTable.Property(e => e.session_time).HasColumnName("session_time");
measureTable.Property(e => e.session_time).IsRequired();
// System Time
measureTable.Property(e => e.system_time).HasColumnName("system_time");
measureTable.Property(e => e.system_time).IsRequired();
// SubSystem
measureTable.Property(e => e.sub_system).HasColumnName("sub_system");
measureTable.Property(e => e.sub_system).IsRequired();
// Data Source
measureTable.Property(e => e.dataSource).HasColumnName("data_source");
measureTable.Property(e => e.dataSource).IsRequired();
// Raw
measureTable.Property(e => e.raw).HasColumnName("raw");
measureTable.Property(e => e.raw).IsRequired();
// Calib
measureTable.Property(e => e.calib).HasColumnName("calib");
measureTable.Property(e => e.calib).IsRequired();
// session id
measureTable.Property(e => e.session_id).HasColumnName("session_id");
measureTable.Property(e => e.session_id).IsRequired();
#endregion Measure Table
}
And here i have the two classes representing the database tables:
SESSION TABLE
/// <summary>
/// Session table
/// </summary>
public class Session_table
{
/// <summary>
/// Id of the session, primary key of the table.
/// </summary>
public int session_id { get; set; }
/// <summary>
/// Session datetime Start.
/// </summary>
public DateTime sessionTimeStart { get; set; } = DateTime.UtcNow;
/// <summary>
/// Session DateTime end.
/// </summary>
public DateTime sessionTimeEnd { get; set; } = DateTime.UtcNow;
/// <summary>
/// Session description.
/// Default: "No description"
/// </summary>
public string description { get; set; } = "No Description";
MEASURE TABLE (Has a foreign key for a one to many relationship: One session -> Many measures)
#region Enum
/// <summary>
/// Subsystem's type.
/// </summary>
public enum SubSystem
{
/// <summary>
/// Zerotype.
/// </summary>
ZERO,
/// <summary>
/// 1 type.
/// </summary>
FIRST,
/// <summary>
/// 2 type.
/// </summary>
SECOND
}
/// <summary>
/// Source of the measure.
/// </summary>
public enum DataSource
{
source1,
source_tbd
}
#endregion Enum
#region Properties
/// <summary>
/// Primary key (unique id) for the measure.
/// Default: 0
/// </summary>
public int measure_id { get; set; } = 0;
/// <summary>
/// DateTime of the session.
/// Default: DateTime min value.
/// </summary>
public DateTime session_time { get; set; } = DateTime.MinValue.ToUniversalTime();
/// <summary>
/// DateTime of the System.
/// Default: DateTime min value.
/// </summary>
public DateTime system_time { get; set; } = DateTime.MinValue.ToUniversalTime();
/// <summary>
/// SubSystem:
/// </summary>
public SubSystem sub_system { get; set; } = SubSystem.FIRST;
/// <summary>
/// Source of the measure.
/// </summary>
public DataSource dataSource { get; set; } = DataSource.source1;
/// <summary>
/// Raw value of the measure.
/// Default: 0
/// </summary>
public int raw { get; set; } = 0;
/// <summary>
/// Calibrated value of the measure.
/// Default: 0
/// </summary>
public double calib { get; set; } = 0;
/// <summary>
/// Foreign Key for One to Many relation.
/// </summary>
public virtual Session_table session { get; set; }
/// <summary>
/// Foreign key for the session table.
/// </summary>
public int session_id { get; set; } = 0;
Now i can connect to the database and insert an object (or list) to both table, i can also select some rows by using
var rows = context.Measures.Select(c => new { c.measure_id, c.raw, c.session_id, c.session.description }).Where(c => c.session_id == 666).ToList();
But when i try to get the all the column (the entire row) it fails in an exception "input string was not in the correct format", i've tried:
var rows = from t in context.Measures
where t.session_id == 666
select t;
var rows = (from t in context.Measures
where t.session_id == 666
select t).AsEnumerable<Measure_table>();
var rows = context.Measures.Where(a => a.session_id == 666).AsEnumerable<Measure_table>();
var rows = from a in context.Measures select a;
var rows = context.Measures;
But none of this works...for sure i'm missing something, but i cannot figure out what!
Thanks for any suggestion
I've also tried:
private void selectTest_2(string connet)
{
using (MySqlConnection connection = new MySqlConnection(connet))
{
try
{
connection.Open();
using (DatabaseContext context = new DatabaseContext(connection, false))
{
foreach (var row in context.Measures)
{
Console.WriteLine($"VALUE: {row.calib}" + Environment.NewLine);
System.Threading.Thread.Sleep(2000);
}
// Save to the database
context.SaveChanges();
}
}
catch (Exception exc)
{
Console.WriteLine($"Exception: {exc}");
}
}
}
But result in the same error. Now i'm sure that i'm missing something important...
I've found a workaround...it seems that the enum properties are the problem, by using a string field everything works, for the moment i'm using this "solution" but how can i safely and properly use the enums?
/// <summary>
/// SubSystem: ZERO, FIRST, SECOND
/// </summary>
public SubSystem sub_system_enum { get; set; } = SubSystem.FIRST;
/// <summary>
/// String properties for database compatibility
/// </summary>
public string sub_system
{
get
{
return this.sub_system_enum.ToString();
}
set
{
this.sub_system_enum = Enum.TryParse<SubSystem>(value, true, out SubSystem val) ? val : default(SubSystem);
}
}
And onModelCreating override method:
// IGnore enums
measureTable.Ignore(e => e.sub_system_enum);
measureTable.Ignore(e => e.dataSource_enum);
Database table:
enter image description here
I'm using nhibernate 5,1,1. Mapping by code
when you add an entry, you send 2 requests
select max (id) From Bred
insert Into Bred (Id, Name, PetType) valuses ({value of max (id)}, text, 1)
I need the field id not to be sent in the insert request and there was no first request. Id auto increment
How can I do that?
public abstract class BaseEntity
{
/// <summary>
/// Ин.
/// </summary>
public virtual int Id { get; set; }
/// <summary>
/// Дата добавления
/// </summary>
public virtual DateTime DateInsert { get; set; }
}
public abstract class BaseMapping<T> : ClassMapping<T> where T : BaseEntity
{
protected BaseMapping(string nameTabel)
{
this.Table(nameTabel);
this.Id(x => x.Id, map =>
{
map.Generator(Generators.Increment);
map.Column("\"Id\"");
});
this.Property(x => x.DateInsert, x =>
{
x.Column("\"DateInsert\"");
x.Insert(false);
x.Update(false);
});
}
}
/// <summary>
/// Справочник пород
/// </summary>
public class Breed : BaseEntity
{
/// <summary>
/// Название
/// </summary>
public virtual string Name { get; set; }
/// <summary>
/// Тип животных
/// </summary>
public virtual PetType PetType { get; set; }
}
public class BreedMap : BaseMapping<Breed>
{
public BreedMap() : base("\"Breed\"")
{
this.Property(x => x.Name, x => x.Column("\"Name\""));
this.Property(x => x.PetType, x => x.Column("\"PetType\""));
}
}
I need the field id not to be sent in the insert request and there was no first request...
In case that our DB is supporting IDENTITY (auto increment on DB side), we should not use Increment, but Native setting (or Identity)
//map.Generator(Generators.Increment);
map.Generator(Generators.Native);
Check the doc for detailed explanation
5.1.5.1. generator
small extract
increment
generates identifiers of any integral type that are unique only when
no other process is inserting data into the same table. Do not use in
a cluster.
...
native/identity
supports identity columns in DB2, MySQL, MS SQL Server and Sybase.
The identifier returned by the database is converted to the property
type using Convert.ChangeType. Any integral property type is thus
supported.
...
I am trying to find the most efficient way to display a set of nested comments from a database schema and into a c# object that i can convert to a serialised JSON object.
My Schema is as follows:
As you can see from the screenshot there is an Update which has a parent issue id (not relevant here) and a Comment. There is also a ParentUpdateID which enables the table to store nested replies for each reply and so on.
I have created a class within c# which i want to convert the results from my Entity Framework call;
/// <summary>
/// The resource view model.
/// </summary>
public class Comment
{
/// <summary>
/// Gets or sets the id.
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Gets or sets the body.
/// </summary>
public string Body { get; set; }
/// <summary>
/// Gets or sets the modified by.
/// </summary>
public string ModifiedBy { get; set; }
/// <summary>
/// Gets or sets the modified date.
/// </summary>
public DateTime ModifiedDate { get; set; }
/// <summary>
/// Gets or sets the created by.
/// </summary>
public string CreatedBy { get; set; }
/// <summary>
/// Gets or sets the created date.
/// </summary>
public DateTime CreatedDate { get; set; }
/// <summary>
/// Gets or sets the parent comment id.
/// </summary>
public Guid? ParentCommentId { get; set; }
/// <summary>
/// Gets or sets the children.
/// </summary>
public List<Comment> Children { get; set; }
}
And here is how i am retrieving the List of Comments / Updates from the database.
List<ClientIssuesUpdate> updates = this.db.ClientIssuesUpdates.Where(i => i.IssueId == issueId).ToList();
Is there a clever way through either a loop or using lync that can order all of the comments showing most recent first, but then display in date order each comments children and so on. (e.g. All comments without a ParentUpdateId would be to level comments)
Any guidance would be helpful so i can learn for the future.
Many thanks
This should order them by date created.
Depending on how deep your comments children gets nested, you would have to add more loops.
List<ClientIssuesUpdate> updates = this.db.ClientIssuesUpdates.Where(i => i.IssueId == issueId).ToList().OrderByDescending(p => p.CreatedDate);
foreach (var comment in updates.Where(comment => comment.Children != null))
{
// order the children
comment.Children = new List<Comment>(comment.Children.OrderByDescending(c => c.CreatedDate));
}
*cant remember if you should use OrderBy<> or OrderByDescending<>
In Datatables 1.10 the ajax server side parameters changed from
public class DataTableParamModel
{
public string sEcho{ get; set; }
public string sSearch{ get; set; }
public int iDisplayLength{ get; set; }
public int iDisplayStart{ get; set; }
public int iColumns{ get; set; }
public int iSortingCols{ get; set; }
public string sColumns{ get; set; }
}
to (API Here http://datatables.net/manual/server-side)
columns[i][data]
columns[i][name]
columns[i][orderable]
columns[i][search][regex]
columns[i][search][value]
columns[i][searchable]
...
draw
length
order[i][column]
order[i][dir]
...
search[regex]
search[value]
start
Some are easy to bind
public class DataTableParamModel
{
public string draw { get; set; }
public int length{ get; set; }
public int start { get; set; }
}
But the new array format looks tricky.
What is the new appropriate model to map the new parameter format?
Here is a model binder and class that will bind these new parameters...
Nuget Package: https://www.nuget.org/packages/Wetware.DataTables
Parameter Model:
[ModelBinder(typeof(DTModelBinder))]
public class DTParameterModel
{
/// <summary>
/// Draw counter. This is used by DataTables to ensure that the Ajax returns from
/// server-side processing requests are drawn in sequence by DataTables
/// </summary>
public int Draw { get; set; }
/// <summary>
/// Paging first record indicator. This is the start point in the current data set
/// (0 index based - i.e. 0 is the first record)
/// </summary>
public int Start { get; set; }
/// <summary>
/// Number of records that the table can display in the current draw. It is expected
/// that the number of records returned will be equal to this number, unless the
/// server has fewer records to return. Note that this can be -1 to indicate that
/// all records should be returned (although that negates any benefits of
/// server-side processing!)
/// </summary>
public int Length { get; set; }
/// <summary>
/// Global Search for the table
/// </summary>
public DTSearch Search { get; set; }
/// <summary>
/// Collection of all column indexes and their sort directions
/// </summary>
public IEnumerable<DTOrder> Order { get; set; }
/// <summary>
/// Collection of all columns in the table
/// </summary>
public IEnumerable<DTColumn> Columns { get; set; }
}
/// <summary>
/// Represents search values entered into the table
/// </summary>
public sealed class DTSearch
{
/// <summary>
/// Global search value. To be applied to all columns which have searchable as true
/// </summary>
public string Value { get; set; }
/// <summary>
/// true if the global filter should be treated as a regular expression for advanced
/// searching, false otherwise. Note that normally server-side processing scripts
/// will not perform regular expression searching for performance reasons on large
/// data sets, but it is technically possible and at the discretion of your script
/// </summary>
public bool Regex { get; set; }
}
/// <summary>
/// Represents a column and it's order direction
/// </summary>
public sealed class DTOrder
{
/// <summary>
/// Column to which ordering should be applied. This is an index reference to the
/// columns array of information that is also submitted to the server
/// </summary>
public int Column { get; set; }
/// <summary>
/// Ordering direction for this column. It will be asc or desc to indicate ascending
/// ordering or descending ordering, respectively
/// </summary>
public string Dir { get; set; }
}
/// <summary>
/// Represents an individual column in the table
/// </summary>
public sealed class DTColumn
{
/// <summary>
/// Column's data source
/// </summary>
public string Data { get; set; }
/// <summary>
/// Column's name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Flag to indicate if this column is orderable (true) or not (false)
/// </summary>
public bool Orderable { get; set; }
/// <summary>
/// Flag to indicate if this column is searchable (true) or not (false)
/// </summary>
public bool Searchable { get; set; }
/// <summary>
/// Search to apply to this specific column.
/// </summary>
public DTSearch Search { get; set; }
}
Model Binder:
/// <summary>
/// Model Binder for DTParameterModel (DataTables)
/// </summary>
public class DTModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
base.BindModel(controllerContext, bindingContext);
var request = controllerContext.HttpContext.Request;
// Retrieve request data
var draw = Convert.ToInt32(request["draw"]);
var start = Convert.ToInt32(request["start"]);
var length = Convert.ToInt32(request["length"]);
// Search
var search = new DTSearch
{
Value = request["search[value]"],
Regex = Convert.ToBoolean(request["search[regex]"])
};
// Order
var o = 0;
var order = new List<DTOrder>();
while (request["order[" + o + "][column]"] != null)
{
order.Add(new DTOrder
{
Column = Convert.ToInt32(request["order[" + o + "][column]"]),
Dir = request["order[" + o + "][dir]"]
});
o++;
}
// Columns
var c = 0;
var columns = new List<DTColumn>();
while (request["columns[" + c + "][name]"] != null)
{
columns.Add(new DTColumn
{
Data = request["columns[" + c + "][data]"],
Name = request["columns[" + c + "][name]"],
Orderable = Convert.ToBoolean(request["columns[" + c + "][orderable]"]),
Searchable = Convert.ToBoolean(request["columns[" + c + "][searchable]"]),
Search = new DTSearch
{
Value = request["columns[" + c + "][search][value]"],
Regex = Convert.ToBoolean(request["columns[" + c + "][search][regex]"])
}
});
c++;
}
return new DTParameterModel
{
Draw = draw,
Start = start,
Length = length,
Search = search,
Order = order,
Columns = columns
};
}
}
Usage:
MyController.cs
public JsonResult DataTablesList(DTParameterModel model)
{
...
}
MVC6
If you're going to MVC6 you no longer need the model binder as MVC6 includes a JQueryFormValueProvider into the default model binder that can bind these values.
The model classes themselves may still be useful, however.
There is a bug to be fixed in 2.1.0 that doesn't allow binding for HttpGet but still works for HttpPost
Give this a try #shoe: datatables-mvc project: https://github.com/ALMMa/datatables-mvc
I changed my javascript to use the legacy ajax params option which uses the old parameters to send to the server. This is done through $.fn.dataTable.ext.legacy.ajax = true; so now my code becomes something like...
$.fn.dataTable.ext.legacy.ajax = true;
var datatable = $('#data-table').DataTable({
"processing": true,
"serverSide": true,
"ajax": "MyController/AjaxHandlerPaging",
"pageLength": 25,
"order": [[2, 'desc']],
"columns": []
});
Know this post is 2 years old but to those who want to use this with ASP.Net Core MVC 6. This is the converted/ upgraded answer provided by #Shoe
Model Binder:
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TrackingAndTraining.Models
{
/// <summary>
/// Model Binder for DTParameterModel (DataTables)
/// </summary>
public class DTModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var request = bindingContext.ActionContext.HttpContext.Request.Form;
// Retrieve request data
var draw = Convert.ToInt32(request["draw"]);
var start = Convert.ToInt32(request["start"]);
var length = Convert.ToInt32(request["length"]);
// Search
var search = new DTSearch
{
Value = request["search[value]"],
Regex = Convert.ToBoolean(request["search[regex]"])
};
// Order
var o = 0;
var order = new List<DTOrder>();
while (!string.IsNullOrEmpty(request["order[" + o + "][column]"]))
{
order.Add(new DTOrder
{
Column = Convert.ToInt32(request["order[" + o + "][column]"]),
Dir = request["order[" + o + "][dir]"]
});
o++;
}
// Columns
var c = 0;
var columns = new List<DTColumn>();
while (!string.IsNullOrEmpty(request["columns[" + c + "][name]"]))
{
columns.Add(new DTColumn
{
Data = request["columns[" + c + "][data]"],
Name = request["columns[" + c + "][name]"],
Orderable = Convert.ToBoolean(request["columns[" + c + "][orderable]"]),
Searchable = Convert.ToBoolean(request["columns[" + c + "][searchable]"]),
Search = new DTSearch
{
Value = request["columns[" + c + "][search][value]"],
Regex = Convert.ToBoolean(request["columns[" + c + "][search][regex]"])
}
});
c++;
}
var result = new DTParameterModel
{
Draw = draw,
Start = start,
Length = length,
Search = search,
Order = order,
Columns = columns
};
bindingContext.Result = ModelBindingResult.Success(result);
return TaskCache.CompletedTask;
}
}
}
Parameter Model:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TrackingAndTraining.Models
{
[ModelBinder(BinderType = typeof(DTModelBinder))]
public class DTParameterModel
{
/// <summary>
/// Draw counter. This is used by DataTables to ensure that the Ajax returns from
/// server-side processing requests are drawn in sequence by DataTables
/// </summary>
public int Draw { get; set; }
/// <summary>
/// Paging first record indicator. This is the start point in the current data set
/// (0 index based - i.e. 0 is the first record)
/// </summary>
public int Start { get; set; }
/// <summary>
/// Number of records that the table can display in the current draw. It is expected
/// that the number of records returned will be equal to this number, unless the
/// server has fewer records to return. Note that this can be -1 to indicate that
/// all records should be returned (although that negates any benefits of
/// server-side processing!)
/// </summary>
public int Length { get; set; }
/// <summary>
/// Global Search for the table
/// </summary>
public DTSearch Search { get; set; }
/// <summary>
/// Collection of all column indexes and their sort directions
/// </summary>
public List<DTOrder> Order { get; set; }
/// <summary>
/// Collection of all columns in the table
/// </summary>
public List<DTColumn> Columns { get; set; }
}
/// <summary>
/// Represents search values entered into the table
/// </summary>
public sealed class DTSearch
{
/// <summary>
/// Global search value. To be applied to all columns which have searchable as true
/// </summary>
public string Value { get; set; }
/// <summary>
/// true if the global filter should be treated as a regular expression for advanced
/// searching, false otherwise. Note that normally server-side processing scripts
/// will not perform regular expression searching for performance reasons on large
/// data sets, but it is technically possible and at the discretion of your script
/// </summary>
public bool Regex { get; set; }
}
/// <summary>
/// Represents a column and it's order direction
/// </summary>
public sealed class DTOrder
{
/// <summary>
/// Column to which ordering should be applied. This is an index reference to the
/// columns array of information that is also submitted to the server
/// </summary>
public int Column { get; set; }
/// <summary>
/// Ordering direction for this column. It will be asc or desc to indicate ascending
/// ordering or descending ordering, respectively
/// </summary>
public string Dir { get; set; }
}
/// <summary>
/// Represents an individual column in the table
/// </summary>
public sealed class DTColumn
{
/// <summary>
/// Column's data source
/// </summary>
public string Data { get; set; }
/// <summary>
/// Column's name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Flag to indicate if this column is orderable (true) or not (false)
/// </summary>
public bool Orderable { get; set; }
/// <summary>
/// Flag to indicate if this column is searchable (true) or not (false)
/// </summary>
public bool Searchable { get; set; }
/// <summary>
/// Search to apply to this specific column.
/// </summary>
public DTSearch Search { get; set; }
}
}
Again all credit goes to #Shoe for original post.
I ran into the same issue when moving to 1.10. Basically, I changed my parameter class like this (getting rid of the unsupported parameters):
public class jQueryDataTableParamModel
{
/// <summary>
/// Request sequence number sent by DataTable,
/// same value must be returned in response
/// </summary>
public string draw { get; set; }
/// <summary>
/// Number of records that should be shown in table
/// </summary>
public int length { get; set; }
/// <summary>
/// First record that should be shown(used for paging)
/// </summary>
public int start { get; set; }
}
In my controller, I get the search value, sort order, and sort column like this:
var searchString = Request["search[value]"];
var sortColumnIndex = Convert.ToInt32(Request["order[0][column]"]);
var sortDirection = Request["order[0][dir]"]; // asc or desc
The full server side binding implementation can be found here. I ran into a similar issue and this was how I went about solving it.
I've run into a issue when using JsonConvert.SerializeObject(addToBasketView) as it seems not to like tha list that i pass into it - until i passed in the list it was working fine - are you not able to pass a list?
Here is my code:
controller:
//We need a list of Automation scripts - this was in Apollo but now we need to pass it in teh message
var automationList = AutomationHelper(retailerId, productId);
var addToBasketView = new AddToBasketView
{
Url = retailerProduct.DeepLink,
Password = (password),
Username = (username),
RetailerProductJson = new RetailerProductJson(retailerProduct),
WidgetImpressionId = id,
Quantity = qty,
MessageId = messageId,
AutomationList = automationList
};
// now turn it into a string
var json = JsonConvert.SerializeObject(addToBasketView);
Addtobasketview.cs:
using System;
using System.Collections.Generic;
namespace WidgetData
{
/// <summary>
/// This is the view that we will give to the AddToBasketForm
/// </summary>
[Serializable]
public class AddToBasketView
{
/// <summary>
/// The Username for the retailer
/// </summary>
public String Username { get; set; }
/// <summary>
/// The password for the retailer
/// </summary>
public String Password { get; set; }
/// <summary>
/// The URl of the thing they want added to the site
/// </summary>
public String Url { get; set; }
/// <summary>
/// The retailer product selected - from this I can get the retailer and the product.
/// </summary>
public RetailerProductJson RetailerProductJson { get; set; }
/// <summary>
/// The widget impression id so that we can attach to the addTobaskets table for recording purposes
/// </summary>
public int WidgetImpressionId { get; set; }
/// <summary>
/// set the quantity
/// </summary>
public int Quantity { get; set; }
/// <summary>
/// The MessageId this is so we can identify it when waiting for a response
/// </summary>
public String MessageId { get; set; }
/// <summary>
/// Automation script list
/// </summary>
public List<AutomationStepScript> AutomationList { get; set; }
}
}
Edit:
AutomationStepScript.cs
using System;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
namespace WidgetData
{
/// <summary>
/// Extends the class created by Linq To SQL, so that we can control in our models section the validity of the data
/// </summary>
[MetadataType(typeof(AuotmationStepScriptValidation))]
public partial class AutomationStepScript
{
/// <summary>
/// Override the to string so that we can use in the delete method to capture details of this record before it is deleted
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format("AutomationStepScript Id = {0}, AutomationStepId = {1}, Sort Order = {2}, Description = {3}, Script = {4}, Evaluate = {5}", Id,AutomationStepId,SortOrder,Description,Script,Evaluate);
}
}
/// <summary>
/// Class to validate my AuotmationStepScript
/// </summary>
public class AuotmationStepScriptValidation
{
/// <summary>
/// AutomationId
/// </summary>
[Required(ErrorMessage = "AutomationStepId is a required field")]
[Range(1, int.MaxValue, ErrorMessage = "AutomationStepId must be valid")]
public int AutomationStepId { get; set; }
/// <summary>
/// Display SortOrder
/// </summary>
[Range(0, int.MaxValue, ErrorMessage = "SortOrder must be valid")]
public int SortOrder { get; set; }
/// <summary>
/// Description
/// </summary>
[StringLength(256, ErrorMessage = "Description maximum length is 256", MinimumLength = 1)]
public String Description { get; set; }
/// <summary>
/// Script
/// </summary>
[AllowHtml]
[StringLength(8000, ErrorMessage = "Script maximum length is 8000")]
public String Script { get; set; }
/// <summary>
/// Evaluate
/// </summary>
public int Evaluate { get; set; }
}
}
AutomationHelper (called in teh controller to get the list:
/// <summary>
/// The helper function to fetch the data so that we can get the scripts for each step for this automation (which we will find from the localParams)
/// </summary>
/// <param name="retailerId"> </param>
/// <param name="productId"> </param>
/// <returns>WE return a List of AutomationStepScripts, this object will be selected further with Lambda expression"></returns>
public List<AutomationStepScript> AutomationHelper(int retailerId, int productId)
{
List<AutomationStepScript> automationStepScripts = null;
var automationStepScriptRepository = new AutomationStepScriptRepository();
var productRepository = new ProductRepository();
var retailerCategoryRepository = new RetailerCategoryRepository();
var product = productRepository.GetProduct(productId);
var categoryId = product.CategoryId;
var retailerCategory = retailerCategoryRepository.GetRetailerCategoryByRetailerCategory(retailerId, categoryId);
// DO we have a retailer category?
if (retailerCategory != null)
{
// Yes, without a valid retailer category we cannot possibly find the automation
// Now here we have the RetailerCategory. The next question is Does this RetailerCategory HAVE an automation set up for it
if (retailerCategory.AutomationId != null)
{
// Yes, we have an automation. So lets get all of the Scripts for all of the steps for this automation
// Get All scripts for all steps for this automation.
automationStepScripts = automationStepScriptRepository.GetAllAutomationStepScriptsForAutomation((int)retailerCategory.AutomationId).ToList();
}
}
return automationStepScripts;
}
I am serializinf it as it bacomes teh body of a message which i am using in SQS which i then use later.
Please let me know if you need any more information.
Thanks.