PostgreSQLCopyHelper Массовая вставка Postgresql Таблица C# Файл с фиксированной шириной
Я пытаюсь Bukl Вставить данные из файла с фиксированной шириной в таблицу Postgresql. Я наткнулся на библиотеку PostgreSQLCopyHelper
https://github.com/bytefish/PostgreSQLCopyHelper
Это моё обновление действия в контроллере (обновлено 15.06.17)
ProductData pd = new ProductData();
public ActionResult Update(q_product q_product, HttpPostedFileBase upload)
{
ProductData pd;
var entities = new List<ProductData>();
PostgreSQLCopyHelper<ProductData> insert;
try
{
if(ModelState.IsValid && upload != null)
{
//uploaded file
Stream stream = upload.InputStream;
//need to use BULK INSERT or MULTIPLE INSERT at this point;
//get the properties (columns) as set in ProductData.cs
using (var fdr = new FileDataReader<ProductData>(stream))
{
//read and get each line on imported file
while ((pd = fdr.ReadLine()) != null)
{
//Lets populate insert
//map table columns with properties
insert = new PostgreSQLCopyHelper<ProductData>("public", "q_product")
.MapUUID("q_guid", x => Guid.NewGuid())
.MapText("q_barcode", x => pd.barcode)
.MapText("q_description", x => pd.description)
.MapText("q_import_size", x => pd.size)
.MapNumeric("q_stocklevel", x => pd.quantity)
.MapText("q_import_vatcode", x => pd.vatCode) //vatcode is numeric in DB, this is a String (new column for this test)
.MapNumeric("q_casecost", x => pd.cost)
.MapNumeric("q_sellprice", x => pd.price);
//add the populated entries as we iterate through the file
entities.Add(pd);
using (var connection = new NpgsqlConnection("Host=192.168.0.52;Database=bolo;Username=western;Password=western"))
{
try
{
connection.Open();
insert.SaveAll(connection, entities);
int lineCount = entities.Count();
TempData["SuccessMessage"] = lineCount+" Records Inserted!";
}
catch (Exception er)
{
TempData["ErrorMessage"] = er.Message;
//TempData["ErrorMessage"] = "Error: importing records!";
}
}
}
}
return RedirectToAction("Index");
}
}
catch(DataException error)
{
TempData["ErrorMessage"] = "Error importing records!";
ModelState.AddModelError("", error.Message);
}
return RedirectToAction("Index");
}
Файл ProductData.cs
public class ProductData
{
[Layout(22, 13)]
public string barcode;
[Layout(49, 25)]
public string description;
[Layout(74, 5)]
public string size;
[Layout(95, 4)]
public int quantity;
[Layout(99, 1)]
public string vatCode;
[Layout(108, 7)]
public decimal cost;
[Layout(115, 7)]
public decimal price;
public override string ToString()
{
return String.Format("string: {0}; string: {1}; string: {2}; int: {3}; string: {4}; decimal {5}; decimal {6}",
barcode, description, size, quantity, vatCode, cost, price
);
}
}
После отладки
юридические лица
параметр в этой строке в действии обновления
insert.SaveAll(connection, entities);
бывает нулевым, поэтому ни одна строка не сохраняется и выдает ошибку "Объект не задан". Теперь из ограниченной документации об этой библиотеке CopyHelper я не могу понять, какой класс или параметр мне нужно сделать IEnumerable, так как SaveAll требует второй параметр IEnumerable
Как вы можете видеть из экрана отладки, мой pd (ProductData) имеет значения, необходимые для хранения в таблице. Как связать это с параметром IEnumerable, необходимым в методе SaveAll?
2 ответа
Я подозреваю, что вы хотите что-то вроде:
public ActionResult Update(q_product q_product, HttpPostedFileBase upload)
{
ProductData pd;
var entities = new List<ProductData>();
PostgreSQLCopyHelper<ProductData> insert = null;
try
{
if(ModelState.IsValid && upload != null)
{
//uploaded file
Stream stream = upload.InputStream;
//need to use BULK INSERT or MULTIPLE INSERT at this point;
//get the properties (columns)
using (var fdr = new FileDataReader<ProductData>(stream))
{
//get each line on file
while ((pd = fdr.ReadLine()) != null)
{
//map table columns with properties
insert = insert ?? new PostgreSQLCopyHelper<ProductData>("public","q_product")
.MapUUID("q_guid", x => Guid.NewGuid())
.MapText("q_barcode", x => this.pd.barcode)
.MapText("q_description", x => this.pd.description)
.MapText("q_size", x => pd.size)
.MapInteger("q_stocklevel", x => this.pd.quantity)
.MapText("q_vatcode", x => pd.vatCode)
.MapMoney("q_casecost", x => this.pd.cost)
.MapMoney("q_sellprice", x => this.pd.price);
entities.Add(pd);
}
}
using (var connection = new NpgsqlConnection("Host=192.168.0.52;Database=tester;Username=test;Password=test"))
{
try
{
connection.Open();
insert.SaveAll(connection, entities);
TempData["SuccessMessage"] = "Records Inserted!";
}
catch (Exception er)
{
TempData["ErrorMessage"] = er.Message;
//TempData["ErrorMessage"] = "Error importing records!";
}
}
return RedirectToAction("Index");
}
}
catch(DataException error)
{
TempData["ErrorMessage"] = "Error importing records!";
ModelState.AddModelError("", error.Message);
}
return RedirectToAction("Index");
}
Главное изменение - заполнение insert
только один раз, а затем добавление записей в entities
как вы перебираете загруженные файлы.
Добавление к удивительному и высоко ценимому ответу mjwillis, если вы не видите раздел комментариев. Следующий код приводит все в порядок: измените отображение с
.MapText("q_barcode", x => this.pd.barcode)
в
.MapVarchar("q_barcode", x => x.barcode)
следующее
//map table columns with properties
insert = insert ?? new PostgreSQLCopyHelper<ProductData>("public", "q_product")
.MapUUID("q_guid", x => Guid.NewGuid())
.MapVarchar("q_barcode", x => x.barcode)
.MapVarchar("q_description", x => x.description)
.MapVarchar("q_import_size", x => x.size)
.MapNumeric("q_stocklevel", x => x.quantity)
.MapVarchar("q_import_vatcode", x => x.vatCode)
.MapNumeric("q_casecost", x => x.cost)
.MapNumeric("q_sellprice", x => x.price);