Я использую Microsoft.EntityFrameworkCore.DbQuery
для возврата POCO из результата табличной функции в моей базе данных. Я заметил, что ни в одном из моих POCO не установлены какие-либо свойства - все они являются значениями по умолчанию - при условии, что их модификаторы доступа отличаются от public
. В моем случае все POCO явно реализуют интерфейсы, поэтому потребитель ничего не знает (или не должен знать) об определениях POCO, поэтому я хочу установить для них значение internal
.
.
Почему POCO должны быть публичными? Или есть способ сделать так, чтобы они не были публичными? Вот пример кода, демонстрирующего это:
CoreLibrary.dll (.NET Standard 2.0)
using System.Collections.Generic;
namespace CoreLibrary
{
public interface IWidgetRepository
{
IReadOnlyCollection<IWidget> FindAllWidgets();
IReadOnlyCollection<IWidget> FindWidgets(string withText);
}
public interface IWidget
{
int ID { get; }
string Name { get; }
string Value { get; }
}
}
DataAccess.dll (.NET Standard 2.0)
using CoreLibrary;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
namespace DataAccess
{
public sealed class WidgetRepositoryApi : IWidgetRepository
{
private DatabaseContext _dbContext;
public WidgetRepositoryApi(string databaseServerName, string databaseName)
=> _dbContext = new DatabaseContext(databaseServerName, databaseName);
public IReadOnlyCollection<IWidget> FindAllWidgets()
=> _dbContext.Widget.ToList();
public IReadOnlyCollection<IWidget> FindWidgets(string withText)
{
string sqlQuery = "SELECT * FROM dbo.fn_SearchWidgetText(@Text)";
var ret = _dbContext.GetWidgetFullTextSearchMatches
.FromSql(sqlQuery, new SqlParameter("@Text",
System.Data.SqlDbType.NVarChar) { Value = withText });
return ret.ToList().AsReadOnly();
}
}
internal partial class DatabaseContext : DbContext
{
private string _dbConnectionString;
internal DatabaseContext(string databaseServerName, string databaseName)
=> _dbConnectionString =
$"Server={databaseServerName};Database={databaseName};Trusted_Connection=True;";
internal virtual DbSet<DBSetWidget> Widget { get; set; }
internal virtual DbQuery<DBQueryWidget> GetWidgetFullTextSearchMatches { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(_dbConnectionString);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DBSetWidget>(entity =>
{
entity.Property(e => e.Id).HasColumnName("ID");
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(50);
entity.Property(e => e.Value).IsRequired();
});
}
}
/********************************************************************
* NOTE: there need to be two widget implementations (POCOs)
* because otherwise the code throws
* System.InvalidCastException: 'Unable to cast object of type
* 'Microsoft.EntityFrameworkCore.Internal.
* InternalDbQuery`1[DataAccess.DBSetWidget]' to type
* 'Microsoft.EntityFrameworkCore.DbSet`1[DataAccess.DBSetWidget]'.'
*******************************************************************/
internal partial class DBQueryWidget : IWidget
{
internal int Id { get; set; }
internal string Name { get; set; }
internal string Value { get; set; }
int IWidget.ID => Id;
string IWidget.Name => Name;
string IWidget.Value => Value;
}
internal partial class DBSetWidget : IWidget
{
internal int Id { get; set; }
internal string Name { get; set; }
internal string Value { get; set; }
int IWidget.ID => Id;
string IWidget.Name => Name;
string IWidget.Value => Value;
}
}
ConsumerConsoleApp.exe (.NET Core 2.1)
using DataAccess;
namespace ConsumerConsoleApp
{
class Program
{
static void Main(string[] args)
{
var repo = new WidgetRepositoryApi(args[0], args[1]);
var allWidgets = repo.FindAllWidgets();
var someWidgets = repo.FindWidgets("facebook");
}
}
}
Таблица виджетов в базе данных SQL
CREATE TABLE [dbo].[Widget](
[ID] [INT] IDENTITY(1,1) NOT NULL,
[Name] [NVARCHAR](50) NOT NULL,
[Value] [NVARCHAR](MAX) NOT NULL,
CONSTRAINT [PK_Widget] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
fn_SearchWidgetText в базе данных
CREATE FUNCTION [dbo].[fn_SearchWidgetText]
(
@Text NVARCHAR(1000)
)
RETURNS TABLE
AS
RETURN
(
SELECT *
FROM dbo.Widget
WHERE CONTAINS(Value, @Text)
)
Если я изменю все мои модификаторы доступа в моем пространстве имен DataAccess
на public
, теперь POCO заполнятся правильно: