Create seed data from sql script - c#

I'm using ORM in my project. Currently seed data is taken from sql scripts but I would like to create seed data basing on my c# code. For example, I have sql:
SET IDENTITY_INSERT [dbo].[State] ON
INSERT INTO [dbo].[State] ([Id], [Code], [Name]) VALUES (1, N'AL', N'Alabama')
INSERT INTO [dbo].[State] ([Id], [Code], [Name]) VALUES (2, N'AK', N'Alaska')
SET IDENTITY_INSERT [dbo].[State] OFF
And instead of it I want to have a string:
new List<State>
{
new State { Id = 1, Code = "AL", Name = "Alabama" },
new State { Id = 2, Code = "AK", Name = "Alaska" }
};
How can I achieve it?

For INSERT statements (as you said you need seed) you can create helper method like this:
public static List<State> ParseSqlScript(string sqlScriptPath)
{
using (var reader = new StreamReader(sqlScriptPath))
{
var sqlScript = reader.ReadToEnd();
var pattern = #"INSERT INTO \[dbo\].\[State\] \(\[Id\], \[Code\], \[Name\]\) VALUES (\(.*?\))";
var regex = new Regex(pattern);
var matches = regex.Matches(sqlScript);
var states = new List<State>();
foreach (Match match in matches)
{
var values = match.Groups[1].Value.Split(new [] { '(', ',',' ',')' }, StringSplitOptions.RemoveEmptyEntries);
var id = int.Parse(values[0]);
var code = values[1].Substring(2, values[1].Length - 3);
var name = values[2].Substring(2, values[2].Length - 3);
foreach (var value in values)
{
var state = new State() { Id = id, Code = code, Name = name };
states.Add(state);
}
}
return states;
}
}
If you also need other CRUD statements you will probably need to get acquainted with some SQL Parser, maybe the Microsoft.SqlServer.SMO.

Try to add the following code, I assume you are working with entity framework:
List<State> states = new List<State>()
{
new State { Id = 1, Code = "AL", Name = "Alabama" },
new State { Id = 2, Code = "AK", Name = "Alaska" }
};
StateDBEntities context = new StateDBEntities();
foreach (State state in states)
{
context.State.Add(state);
}
context.SaveChanges();

List<State> states = new List<State>();
using (SqlConnection connection = new SqlConnection("conn_string"))
{
string query = "SELECT Id, Code, Name FROM State";
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
State state = new State { Id = (int)reader["Id"], Code = reader["Code"].ToString(), Name = reader["Name"].ToString() };
states.Add(state);
}
}
}
}
Call the select query(here I'm writing the query, but it should be avoided, you can use Stored Procedure). Get all columns using ExecuteReader and add all the rows to list one by one.

Related

Nest Json data from MySql queries in C#

Im trying to make a nested json with data get from a MySQL DB
For the moment i got
//Obtener el root de info
public List<Root> GetRoot()
{
using (var conexion = ObtenerConexion())
{
conexion.Open();
var query = #"SELECT id AS Id, fullname AS NombreCurso, MID(fullname, INSTR(fullname, ""RLAB""), 20) AS codigoOferta
FROM mo_course
WHERE MID(fullname, INSTR(fullname, ""RLAB""), 20) != '';";
var resultado = conexion.Query<Root>(query);
foreach (var item in resultado)
{
Root root = new Root();
root.codigoOferta = item.codigoOferta;
root.listaAlumnos = new List<ListaAlumno>();
roots.Add(root);
conexion.Close();
}
return roots;
}
}
public List<ListaAlumno> GetAlumnos(string codigoOferta)
{
using (var conexion = ObtenerConexion())
{
conexion.Open();
var query = #"SELECT mo_role_assignments.userid AS Id, firstname AS Nombre, lastname AS Apellido, LEFT(mo_user.idnumber, LENGTH(mo_user.idnumber - 2)) AS rutAlumno,
RIGHT(mo_user.idnumber, 1) AS dvAlumno, email AS Correo, mo_course.fullname AS NombreCurso, mo_course.idnumber AS codigoOferta,
FROM_UNIXTIME(startdate) AS fechaInicio, FROM_UNIXTIME(enddate) AS fechaFin
FROM mo_course
INNER JOIN mo_context ON mo_context.instanceid = mo_course.id
INNER JOIN mo_role_assignments ON mo_context.id = mo_role_assignments.contextid
INNER JOIN mo_user ON (mo_role_assignments.userid = mo_user.id)";
var resultado = conexion.Query<ListaAlumno>(query);
foreach (var item in resultado)
{
ListaAlumno alumno = new ListaAlumno();
alumno.codigoOferta = item.codigoOferta;
alumno.rutAlumno = item.rutAlumno;
alumno.dvAlumno = item.dvAlumno;
alumno.tiempoConectividad = 0;
alumno.estado = 0;
alumno.porcentajeAvance = 0;
alumno.fechaInicio = item.fechaInicio;
alumno.fechaFin = item.fechaFin;
alumno.fechaEjecucion = "";
alumno.listaModulos = new List<ListaModulo>();
listaAlumnos.Add(alumno);
}
conexion.Close();
}
return listaAlumnos;
}
}
but i cant find a way to do the variable to nest the data, since i getting the data as direct query the parameter "codigoOferta" in GetAlumnos is not working
The idea its to do the following
{
"rutOtec": "9999999-9",
"idSistema": 1350,
"token": "AAAAAA-ASSS-DDDDd-8FFF-2FFFFFFFFD2",
"codigoOferta": "RSJ-D444-555-666666",
"codigoGrupo": "RSJ-D444-555-666666",
"codigoEnvio": "RSJ-D444-555-666666",
"listaAlumnos": [
{
"rutAlumno": 255544466,
"dvAlumno": "4",
"tiempoConectividad": 199112,
"estado": 1,
"porcentajeAvance": 99,
"fechaInicio": "2022-07-28",
"fechaFin": "2022-10-24",
"fechaEjecucion": "2022-10-24",
"listaModulos": [
{
"codigoModulo": "ARS027773588877",
"tiempoConectividad": 7964,
"estado": 1,
"porcentajeAvance": 100,
"fechaInicio": "2022-07-28",
"fechaFin": "2022-10-24",
"listaActividades": [
{
"codigoActividad": "Excel"
},
{
"codigoActividad": "Video interactivo de introducci\u00f3n a Excel"
},
but since for each student in listaAlumno the data change i need to nest the variables

How do I remove a line from the list based on the ID of that line?

I've been trying to figure this out for the past few days, but I just can't seem to get it work.
So I have a txt file which has this format:
id;könyvcím;szerző;kiadó;kiadási év;
I am using a structs and a list such as this:
public static List<Books> BooksList = new List<Books>();
public struct Books
{
public int id;
public string title;
public string writer;
public string publisher;
public int published_year;
}
And I'm also putting all these into a List based on the struct like this:
StreamReader booksRead = new StreamReader("konyvek.txt", Encoding.UTF8);
booksRead.ReadLine();
while (!booksRead.EndOfStream)
{
string[] split = booksRead.ReadLine().Split(';');
Books inRead = new Books();
inRead.id = Convert.ToInt32(split[0]);
inRead.title = split[1];
inRead.writer = split[2];
inRead.publisher = split[3];
inRead.published_year = Convert.ToInt32(split[4]);
BooksList.Add(inRead);
}
booksRead.Close();
All I want is, for example, to find where the line with ID 2 is, and remove that line from my textfile. I've tried to get the index of the line I want, and remove it like that from my textfile, but it even fails to get the index, I tried using IndexOf, FindIndex and trying to go on a loop. I'm pretty sure my struct is not happy with me for using it like that because I get errors such as this when I run my code:
System.InvalidCastException: 'Unable to cast object of type 'Books' to
type 'System.IConvertible'.'
Here is the way I'm trying to get the index of the line I want to remove
Books item = new Books();
for (int i = 0; i < BooksList.Count; i++)
{
if (Convert.ToInt32(textBox_id_delete.Text) == item.id)
{
RemoveAt = item.id;
}
}
int index = BooksList.FindIndex(x => Convert.ToInt32(x) == RemoveAt);
MessageBox.Show(Convert.ToString(index));
I'm pretty sure I'm approaching this extremely wrong, and I'd accept any kind of help.
You are doing it completely wrong for a number of reasons.
First, how would you do that the way you are doing:
void Main()
{
var filename = #"c:\myFolder\mybooklist.txt";
// read into an enumerable
var books = File.ReadAllLines(filename)
.Select(x => x.Split(';'))
.Select(x => new Book {
Id = int.TryParse(x[0], out int bookId)?bookId:0,
Title = x[1],
Writer = x[2],
Publisher = x[3],
Published_year=int.TryParse(x[4], out int year)?year:0
});
// remove the one with id 2
// and save back
var otherBooks = books.Where(b => b.Id != 2);
File.WriteAllLines(filename, otherBooks.Select(b => $"{b.Id};{b.Title};{b.Writer};{b.Publisher};{b.Published_year}"));
}
public struct Book
{
public int Id;
public string Title;
public string Writer;
public string Publisher;
public int Published_year;
}
And now what is wrong with this.
A text file is not a database but you are trying to use a text file as a database.
With a text file, you are not actually doing any control here, if the ID is unique or not (there might be N books with the ID 2).
(Side matter) You are using C#, but looks like you are coming from another language and not using the naming conventions at all.
IMHO, instead you should simply use a database, an embedded one for example like LiteDb or Sqlite. If you care to see a sample with LiteDb or Sqlite, let me know.
EDIT: I am adding SQLite and LiteDb samples. In either case, you would need to add Sqlite.Data.Sqlite and LiteDB respectively from Nuget and add using statements.
In case of SQLite, please note that you could use Linq adding some drivers. I directly used the ADO.Net commands and didn't use a Book class for mapping.
LiteDB, being a NoSQL database written in C# for C#, can directly use objects and support Linq out of the box.
Samples show only the surface for both.
SQLite sample:
private static readonly string dataFile = #"d:\temp\books.s3db";
void Main()
{
CreateDb(dataFile);
SeedSampleData(dataFile);
// List the current data
Console.WriteLine("Current Data");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
DeleteSampleRow(dataFile);
// List the current data
Console.WriteLine("After deleting");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
}
void DeleteSampleRow(string dbName)
{
string deleteById = "delete from books where id = #id";
string deleteByTitle = "delete from books where Title = #title";
string deleteByWriter = "delete from books where Writer = #writer";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmdById = new SQLiteCommand(deleteById, cn))
using (SQLiteCommand cmdByTitle = new SQLiteCommand(deleteByTitle, cn))
using (SQLiteCommand cmdByWriter = new SQLiteCommand(deleteByWriter, cn))
{
cmdById.Parameters.Add("#id", DbType.Int32).Value = 2; // delete the book with id = 2
cmdByTitle.Parameters.Add("#title", DbType.String).Value = $"Sample Title #5"; // delete all books having title "Sample Title #5"
cmdByWriter.Parameters.Add("#writer", DbType.String).Value = $"Sample Writer #3"; // delete all books written by "Sample Writer #3"
cn.Open();
cmdById.ExecuteNonQuery();
cmdByTitle.ExecuteNonQuery();
cmdByWriter.ExecuteNonQuery();
cn.Close();
}
}
void ListData(string dbName)
{
string selectCommand = "select * from books";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmd = new SQLiteCommand(selectCommand, cn))
{
cn.Open();
var r = cmd.ExecuteReader();
while (r.Read())
{
Console.WriteLine($"{r["id"]},{r["title"]},{r["writer"]},{r["publisher"]},{r["published_year"]}");
}
cn.Close();
}
}
private void CreateDb(string dbName)
{
if (File.Exists(dbName)) // if it exists, delete and create afresh, just for sampling
{
File.Delete(dbName);
}
string createTable = #"Create Table books (
id int primary key not null,
title varchar(500) not null,
writer varchar(100) not null,
publisher varchar(100) not null,
published_year int not null
)";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmd = new SQLiteCommand(createTable, cn))
{
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
}
private void SeedSampleData(string dbName)
{
string insertCommand = #"insert into books
(id, title, writer, publisher, published_year)
values
(#id, #title, #writer, #publisher, #year);";
using (SQLiteConnection cn = new SQLiteConnection($"Data Source={dbName}"))
using (SQLiteCommand cmd = new SQLiteCommand(insertCommand, cn))
{
cmd.Parameters.Add("#id", DbType.Int32);
cmd.Parameters.Add("#title", DbType.String);
cmd.Parameters.Add("#writer", DbType.String);
cmd.Parameters.Add("#publisher", DbType.String);
cmd.Parameters.Add("#year", DbType.Int32);
Random r = new Random();
cn.Open();
int id = 1;
using (SQLiteTransaction transaction = cn.BeginTransaction())
{
cmd.Parameters["#id"].Value = id++;
cmd.Parameters["#title"].Value = $"Around the World in Eighty Days";
cmd.Parameters["#writer"].Value = $"Jules Verne";
cmd.Parameters["#publisher"].Value = $"Le Temps, Pierre-Jules Hetzel";
cmd.Parameters["#year"].Value = 1873;
cmd.ExecuteNonQuery();
cmd.Parameters["#id"].Value = id++;
cmd.Parameters["#title"].Value = $"A Tale of Two Cities";
cmd.Parameters["#writer"].Value = $"Charles Dickens";
cmd.Parameters["#publisher"].Value = $"Chapman & Hall";
cmd.Parameters["#year"].Value = 1859;
cmd.ExecuteNonQuery();
// add dummy 10 more rows
for (int i = 0; i < 10; i++)
{
cmd.Parameters["#id"].Value = id++;
cmd.Parameters["#title"].Value = $"Sample Title #{i}";
cmd.Parameters["#writer"].Value = $"Sample Writer #{r.Next(1, 5)}";
cmd.Parameters["#publisher"].Value = $"Sample Publisher #{i}";
cmd.Parameters["#year"].Value = r.Next(1980, 2022);
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
// databases generally use some indexes
new SQLiteCommand(#"Create Index if not exists ixId on books (id);", cn).ExecuteNonQuery();
new SQLiteCommand(#"Create Index if not exists ixTitle on books (title);", cn).ExecuteNonQuery();
new SQLiteCommand(#"Create Index if not exists ixWriter on books (writer);", cn).ExecuteNonQuery();
new SQLiteCommand(#"Create Index if not exists ixPublisher on books (publisher);", cn).ExecuteNonQuery();
cn.Close();
}
}
LiteDb sample:
private static readonly string dataFile = #"d:\temp\books.litedb";
void Main()
{
//CreateDb(dataFile); // this step is not needed with LiteDB
// instead we just simply delete the datafile if it exists
// for starting afresh
// if it exists, delete and create afresh, just for sampling
// so you can run this same sample over and over if you wish
if (File.Exists(dataFile))
{
File.Delete(dataFile);
}
SeedSampleData(dataFile);
// List the current data
Console.WriteLine("Current Data");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
DeleteSampleRow(dataFile);
// List the current data
Console.WriteLine("After deleting");
Console.WriteLine("".PadRight(100, '='));
ListData(dataFile);
Console.WriteLine("".PadRight(100, '='));
}
void DeleteSampleRow(string dbName)
{
using (var db = new LiteDatabase(dbName))
{
var bookCollection = db.GetCollection<Book>("Books");
// by ID
bookCollection.Delete(2);
// by Title
bookCollection.DeleteMany(c => c.Title == "Sample Title #5");
// by Writer
bookCollection.DeleteMany(c => c.Writer == "Sample Writer #3");
}
}
void ListData(string dbName)
{
using (var db = new LiteDatabase(dbName))
{
var bookCollection = db.GetCollection<Book>("Books");
foreach (var book in bookCollection.FindAll())
{
Console.WriteLine($"{book.Id},{book.Title},{book.Writer},{book.Publisher},{book.Published_year}");
}
}
}
private void SeedSampleData(string dbName)
{
Random r = new Random();
var books = new List<Book> {
new Book {Title="Around the World in Eighty Days",Writer = "Jules Verne",Publisher = "Le Temps, Pierre-Jules Hetzel",Published_year= 1873},
new Book {Title="A Tale of Two Cities",Writer = "Charles Dickens",Publisher = "Chapman & Hall",Published_year= 1859},
};
// add dummy 10 more rows
books.AddRange(Enumerable.Range(0, 10).Select(i => new Book
{
Title = $"Sample Title #{i}",
Writer = $"Sample Writer #{r.Next(1, 5)}",
Publisher = $"Sample Publisher #{i}",
Published_year = r.Next(1980, 2022)
}));
using (var db = new LiteDatabase(dbName))
{
var bookCollection = db.GetCollection<Book>("Books");
bookCollection.InsertBulk(books);
// databases generally use some indexes
// create the same indexes that we created in SQLite sample
bookCollection.EnsureIndex(c => c.Id);
bookCollection.EnsureIndex(c => c.Title);
bookCollection.EnsureIndex(c => c.Writer);
bookCollection.EnsureIndex(c => c.Publisher);
}
}
public class Book
{
public int Id {get;set;}
public string Title {get;set;}
public string Writer {get;set;}
public string Publisher {get;set;}
public int Published_year {get;set;}
}
welcome to SO. I'm going to assume you've got a reason for keeping the data in a text file. As several answers have suggested if you need it in a text file the easiest thing to do is to simply create a new file with the lines you want.
One way to do that is to make use of a interator function to filter the lines. This lets you easily use the .NET File class to do the rest - creating the new file and removing the old if you want to. Often keeping the old file and archiving it can be useful too but anyway, here's a way to filter the lines.
static void Main(string[] _)
{
var filteredLines = FilterOnID(File.ReadAllLines("datafile.txt"), "2");
File.WriteAllLines("updated.datafile.txt", filteredLines);
// rename if necessary
File.Delete("datafile.txt");
File.Move("updated.datafile.txt", "datafile.txt");
}
static IEnumerable<string> FilterOnID(IEnumerable<string> lines, string id)
{
foreach (var line in lines)
{
var fields = line.Split(';');
if (fields.Length != 0 || !string.IsNullOrEmpty(fields[0]))
{
if (id == fields[0])
continue;
}
yield return line;
}
}
To test I added simple file like so:
1;field1;field2;field3
2;field1;field2;field3
3;field1;field2;field3
4;field1;field2;field3
5;field1;field2;field3
6;field1;field2;field3
And after running you get this:
1;field1;field2;field3
3;field1;field2;field3
4;field1;field2;field3
5;field1;field2;field3
6;field1;field2;field3
When you put books into a list from a file, you can search the book for remove from BooksList.
Delete it and save BooksList into a file.
var removeBook = BookList.FirstOrDefault(book => book.id == removeId);
if (removeBook != null)
{
BookList.Remove(removeBook);
}
var booksAsString = BookList.Select(book => $"{book.id};{book.title};{book.writer};{book.publisher};{book.published_year}");
File.WriteAllLines("konyvek.txt", booksAsString, Encoding.UTF8);

An exception of type 'MySql.Data.MySqlClient.MySqlException' occurred

I am trying to create a new UserFingerprintModel that spans two database tables. One is from PaymentFingerprint and one is from PaymentFingerprintGrant. For my service tests, I created these two sql statments:
private const string _ADD_FINGERPRINT_QUERY = #"
INSERT INTO FinOps.PaymentFingerprint(
CreateDate,
Fingerprint,
PaymentTypeId,
FingerprintTypeId
)
VALUES (
NOW(),
#pFingerprint,
#pPaymentTypeId,
#pFingerprintTypeId
); SELECT LAST_INSERT_ID();";
And then in order to create the FingerprintGrant, I need the fingerprintId, which explains the `SELECT LAST_INSERT_ID();" above.
Here is my FingerprintGrant sql string:
private const string _ADD_FINGERPRINT_GRANT_QUERY = #"
INSERT INTO FinOps.PaymentFingerprintGrant(
PaymentFingerprintId,
CreateDate,
DepositLimit,
DepositLimitIntervalDays,
IsDeleted,
PaymentFingerprintStatusId,
UserId
)
VALUES (
#pPaymentFingerprintId,
NOW(),
#pDepositLimit,
#pDepositLimitIntervalDays,
#pIsDeleted,
#pPaymentFingerprintStatusId,
#pUserId
);";
I then try to use MySqlConnection. Here is my code below:
// Returns the last insert id
public int AddUserFingerprint (string fingerprint, int paymentTypeId, int fingerprintTypeId)
{
using (var conn = new MySqlConnection(_finopsConnection))
return conn.Execute(_ADD_FINGERPRINT_QUERY,
new
{
pFingerprint = fingerprint,
pPaymentTypeId = paymentTypeId,
pFingerprintTypeId = fingerprintTypeId
}, commandType: CommandType.Text);
}
public void AddUserFingerprintGrant(int paymentFingerprintId, DateTime createdDate, int depositLimit, int depositLimitInteveralDays, int isDeleted, int userId, int paymentFingerprintStatusId, string fingerprint, int paymentTypeId, int fingerprintTypeId)
{
using (var conn = new MySqlConnection(_finopsConnection))
conn.ExecuteScalar(_ADD_FINGERPRINT_GRANT_QUERY,
new
{
pPaymentFingerprintId = AddUserFingerprint(fingerprint, paymentTypeId, fingerprintTypeId),
pDepositLimit = depositLimit,
pDepositLimitIntervalDays = depositLimitInteveralDays,
pIsDeleted = isDeleted,
pPaymentFingerprintStatusId = paymentFingerprintStatusId,
pUserId = userId
}, commandType: CommandType.Text);
}
And this is where I call these two methods in my Service Test
[Test]
public void TestGetFingerprintById()
{
HttpStatusCode status;
var userFingerprint = CreateRandomFingerprintGrant();
var paymentFingerprintId = AddUserFingerprint(userFingerprint.Fingerprint, userFingerprint.PaymentTypeId, userFingerprint.FingerprintTypeId);
AddUserFingerprintGrant(paymentFingerprintId, userFingerprint.CreateDate, userFingerprint.DepositLimit,
userFingerprint.DepositLimitIntervalDays, userFingerprint.IsDeleted, userFingerprint.UserId,
userFingerprint.PaymentFingerprintStatusId, userFingerprint.Fingerprint, userFingerprint.PaymentTypeId,
userFingerprint.FingerprintTypeId);
var query = new GetFingerprintByIdQuery()
{
UserId = userFingerprint.UserId,
FingerprintId = paymentFingerprintId
};
var resp = _hermesDriver.GetFingerprintInfoById(query, out status);
}
However, when I run the service test, I get this error: TestGetFingerprintById [0:01.608] Failed: MySql.Data.MySqlClient.MySqlException : Duplicate entry '1-3b590375-06d2-4923-a266-d98d44ab2b0f' for key 'idx_payment_type_fingerprint_uniq'
The fingerprint is generated in my helper method:
public AddUserFingerprintModel CreateRandomFingerprintGrant()
{
var fingerprint = Guid.NewGuid().ToString();
var userFingerprintDto = new AddUserFingerprintModel()
{
Fingerprint = fingerprint,
UserId = 100001,
IsDeleted = 0,
UpdatedDate = DateTime.Today,
PaymentTypeId = 1,
DepositLimit = 10000,
PaymentFingerprintGrantId = 100010,
Version = 1,
PaymentFingerprintStatusId = 1,
CreateDate = DateTime.Today,
FingerprintTypeId = 1,
DepositLimitIntervalDays = 5
};
return userFingerprintDto;
}
I don't really understand why i'm getting this exception. Even if I hardcode the fingerprint string to random gibberish, I still get this exception/error.
Any help would be greatly appreciated!
Make sure that you have all the variables for EACH column.

C# retrieve stored procedure results

Procedure (modified):
alter procedure searchProgramUnitResult(
#id char(10)
)
as
begin
select id from table1 where id = #id
end
Sam procedure in the DBML Designer (after importing the procedure to the MVC project):
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.searchProgramUnit")]
public ISingleResult<searchProgramUnitResult> searchProgramUnit([global::System.Data.Linq.Mapping.ParameterAttribute(DbType="VarChar(10)")] ref string id){
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())),id);
id = ((string)(result.GetParameterValue(0)));
return ((ISingleResult<searchProgramUnitResult>)(result.ReturnValue));
}
Question is, how do I retrieve the result set in another C# class?
public ??Data-type search (string id){
DataContextClass db = new DataContextClass();
??Datatype results = db.searchProgramUnit(id);
return results;
}
If you have mapped the stored procedure in your DbContext you can call it like that:
using (var context = new DataContextClass())
{
var courses = context.searchProgramUnit("1");
foreach (table1 cs in table1s)
Console.WriteLine(cs.Name);
}
another approach which works also with Code First:
using (var ctx = new DataContextClass())
{
var idParam = new SqlParameter
{
ParameterName = "id",
Value = "1"
};
var table1List = ctx.Database.SqlQuery<table1>("exec searchProgramUnitResult #id ", idParam).ToList<table1>();
foreach (table cs in table1List)
Console.WriteLine("Name: {0}", cs.Name);
}
table1 is your entity/class name!
Are you asking about the data type?
public List<string> search (string id){
DataContextClass db = new DataContextClass();
List<string> results = db.searchProgramUnit(id).ToList();
return results;
}

Using Dapper.TVP TableValueParameter with other parameters

I have a procedure that takes in a table-valued parameter, along with others:
CREATE PROCEDURE [dbo].[Update_Records]
#currentYear INT,
#country INT,
#records Record_Table_Type READONLY
AS
and am trying to call this with Dapper.TVP.
Here is the code I have so far:
var recordsParameter = new List<SqlDataRecord>();
// This metadata matches 'Record_Table_Type' in the Database
var recordsMetaData = new[]
{
new SqlMetaData("OriginalValue", SqlDbType.Decimal, 19, 4),
new SqlMetaData("NewValue", SqlDbType.Decimal, 19, 4),
new SqlMetaData("NewPercent", SqlDbType.Decimal, 7, 2),
};
foreach (var r in records)
{
var record = new SqlDataRecord(recordsMetaData);
record.SetDecimal(0, r.OriginalValue);
record.SetDecimal(1, r.NewValue);
record.SetDecimal(2, r.NewPercent);
recordsParameter.Add(record);
}
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
});
var recordsParam = new TableValueParameter("#records", "Record_Table_Type", recordsParameter);
using (var connection = ConnectionFactory.GetConnection())
{
connection.Execute("Update_Records", ???, commandType: CommandType.StoredProcedure);
}
My issue is how do I pass both sets of parameters to the procedure in the call to Dapper Execute()?
I have tried:
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
records = new TableValueParameter("#records", "Record_Table_Type", recordsParameter);
});
connection.Execute("Update_Records", spParams, commandType: CommandType.StoredProcedure);
and
connection.Execute("Update_Records", new Object[] { spParams, recordsParam }, commandType: CommandType.StoredProcedure);
Both call the procedure, but pass an empty table parameter ( SELECT COUNT(*) FROM #records returns 0 )
I can't seem to find any actual documentation or source for Dapper.TVP, so the whole thing is very confusing, and the 2nd parameter to .Execute() is just a dynamic so that again doesn't tell me what I can and can't pass to it.
Any ideas?
I am on mobile and may be misunderstanding the question, but this should be just:
DataTable records = ...
connection.Execute("Update_Records",
new {
currentYear = filter.currentYear,
country = filter.country,
records
},
commandType: CommandType.StoredProcedure
);
Based on an answer from Mark Gravell here: Does Dapper support SQL 2008 Table-Valued Parameters?
I changed my code to no longer use Dapper.TVP and instead just use a DataTable so the code is now:
var recordsTable = new DataTable();
recordsTable.Columns.Add("NewValue", typeof(Decimal));
foreach (var netRevenue in records)
{
var row = recordsTable.NewRow();
row[0] = netRevenue.NewValue;
recordsTable.Rows.Add(row);
}
recordsTable.EndLoadData();
var spParams = new DynamicParameters(new
{
currentYear = filter.currentYear,
country = filter.country,
records = recordsTable.AsTableValuedParameter("Record_Table_Type")
});
using (var connection = ConnectionFactory.GetConnection())
{
connection.Execute("Update_Records", spParams, commandType: CommandType.StoredProcedure);
}
And this works.

Categories

Resources