Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# TPL数据流块从单个输入产生多个输出_C#_Task Parallel Library_Tpl Dataflow - Fatal编程技术网

C# TPL数据流块从单个输入产生多个输出

C# TPL数据流块从单个输入产生多个输出,c#,task-parallel-library,tpl-dataflow,C#,Task Parallel Library,Tpl Dataflow,我已经开始研究TPL数据流作为处理工作流的解决方案 处理工作流的要点是从多个表中读入输入消息,并从中创建四个反射对象,然后将它们持久化到其他四个表中,因此每个输入消息都应生成四条新消息 我无法确定可以帮助创建四个对象的预定义块中的一个,起初TransformManyBlock似乎是我要寻找的,但它返回相同类型的多个对象,其中我将有四种类型 问题示例 我们有两个表,其中包含来自两个遗留系统的员工详细信息,它们的实体如下所示 public partial class EmployeeTblA {

我已经开始研究TPL数据流作为处理工作流的解决方案

处理工作流的要点是从多个表中读入输入消息,并从中创建四个反射对象,然后将它们持久化到其他四个表中,因此每个输入消息都应生成四条新消息

我无法确定可以帮助创建四个对象的预定义块中的一个,起初TransformManyBlock似乎是我要寻找的,但它返回相同类型的多个对象,其中我将有四种类型

问题示例

我们有两个表,其中包含来自两个遗留系统的员工详细信息,它们的实体如下所示

public partial class EmployeeTblA
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
    public int Number { get; set; }
    public string Street { get; set; }
    public string PostCode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeTblB
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}
public class BaseEmployee
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }
}
public partial class EmployeeName
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public string Name { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeAge
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public int Age { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeAddress
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}
我们希望从两个系统获取数据,并将数据放入我们闪亮的新系统中,为此,我们需要将旧系统中的实体转换为新系统中使用的实体。首先,我们将旧系统中的实体转换为如下所示的基类

public partial class EmployeeTblA
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
    public int Number { get; set; }
    public string Street { get; set; }
    public string PostCode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeTblB
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}
public class BaseEmployee
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }
}
public partial class EmployeeName
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public string Name { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeAge
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public int Age { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeAddress
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}
然后我们想从基类中创建三个新对象,它们表示新系统的实体,如下所示

public partial class EmployeeTblA
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int Age { get; set; }
    public int Number { get; set; }
    public string Street { get; set; }
    public string PostCode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeTblB
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}
public class BaseEmployee
{
    public int Id { get; set; }
    public int System { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }
}
public partial class EmployeeName
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public string Name { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeAge
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public int Age { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}

public partial class EmployeeAddress
{
    public int Id { get; set; }
    public int System { get; set; }
    public int LegacyId { get; set; }
    public string Address { get; set; }
    public string Postcode { get; set; }

    public virtual EmployeeSystem SystemNavigation { get; set; }
}
上述示例中我的第三方物流的大致流程

  • 将数据库中的表中的数据读取到转换为公共对象的TranformBlock中,对于每个遗留系统,这会下降两次

  • 每个TranformBlock链接到一个BatchBlock,以对所有输入流进行分组

  • BatchBlock链接到一个块,该块将接受输入并从输入数据创建两个新对象EmployeeName和EmployeeAge

  • 然后,该块将链接到动作块和采取动作的动作,并将它们保存到数据库中各自的表中


  • 我知道我可以创建一个自定义块,但我不知道如何使用它来使用数据流向四个单独的链接ActionBlock提供输出,有人能给我指出正确的方向吗?

    广播块是我最终使用的组件,我使用它将BaseEmployee对象广播到其他输出流,分离出我需要创建的反射对象

    完整管道如下所示

             _transEmployeeA = new TransformBlock<EmployeeTblA, BaseMsg>((input) =>
             {
                return new BaseMsg()
                {
                    Id = input.Id,
                    System = input.System,
                    Name = string.Concat(input.Forename, " ", input.Surname),
                    Age = input.Age,
                    Address = string.Concat(input.Number, " ", input.Street),
                    Postcode = input.PostCode
                };
            });
    
            _transEmployeeB = new TransformBlock<EmployeeTblB, BaseMsg>((input) =>
            {
                return new BaseMsg()
                {
                    Id = input.Id,
                    System = input.System,
                    Name = input.Name,
                    Age = input.Age,
                    Address = input.Address,
                    Postcode = input.Postcode
                };
            });
    
            _broadcastBaseMsg = new BroadcastBlock<BaseMsg>(null);
    
            _transEmployeeName = new TransformBlock<BaseMsg, EmployeeName>((baseMsg) =>
            {
                return new EmployeeName()
                {
                    System = baseMsg.System,
                    LegacyId = baseMsg.Id,
                    Name = baseMsg.Name
                };
            });
    
            _transEmployeeAge = new TransformBlock<BaseMsg, EmployeeAge>((baseMsg) =>
            {
                return new EmployeeAge()
                {
                    System = baseMsg.System,
                    LegacyId = baseMsg.Id,
                    Age = baseMsg.Age
                };
            });
    
            _transEmployeeAddress = new TransformBlock<BaseMsg, EmployeeAddress>((baseMsg) =>
            {
                return new EmployeeAddress()
                {
                    System = baseMsg.System,
                    LegacyId = baseMsg.Id,
                    Address = baseMsg.Address,
                    Postcode = baseMsg.Postcode
                };
            });
    
    
            _bufferEmployeeName = new BufferBlock<EmployeeName>();
            _bufferEmployeeAge = new BufferBlock<EmployeeAge>();
            _bufferEmployeeAddress = new BufferBlock<EmployeeAddress>();
    
            _actionEmployeeName = new ActionBlock<EmployeeName>((output) =>
            {
                using (var cxt = new SandboxContext())
                {
                    cxt.EmployeeNames.Add(output);
                    cxt.SaveChanges();
                }
            });
    
            _actionEmployeeAge = new ActionBlock<EmployeeAge>((output) =>
            {                
                using (var cxt = new SandboxContext())
                {
                    cxt.EmployeeAges.Add(output);
                    cxt.SaveChanges();
                }                
            });
    
            _actionEmployeeAddress = new ActionBlock<EmployeeAddress>((output) =>
            {                
                using (var cxt = new SandboxContext())
                {
                    cxt.EmployeeAddresses.Add(output);
                    cxt.SaveChanges();
                }               
            });
    
            var linkOpts = new DataflowLinkOptions()
            {
                PropagateCompletion = true
            };
    
            // Transform Employees and pass to Batch
            _transEmployeeA.LinkTo(_broadcastBaseMsg, linkOpts);
            _transEmployeeB.LinkTo(_broadcastBaseMsg, linkOpts);
    
            // Transform Broadcast to respective outputs
            _broadcastBaseMsg.LinkTo(_transEmployeeName, linkOpts);
            _broadcastBaseMsg.LinkTo(_transEmployeeAge, linkOpts);
            _broadcastBaseMsg.LinkTo(_transEmployeeAddress, linkOpts);
    
            // Add outputs to Buffer
            _transEmployeeName.LinkTo(_bufferEmployeeName, linkOpts);
            _transEmployeeAge.LinkTo(_bufferEmployeeAge, linkOpts);
            _transEmployeeAddress.LinkTo(_bufferEmployeeAddress, linkOpts);
    
            // Persist outputs to DB
            _bufferEmployeeName.LinkTo(_actionEmployeeName, linkOpts);
            _bufferEmployeeAge.LinkTo(_actionEmployeeAge, linkOpts);
            _bufferEmployeeAddress.LinkTo(_actionEmployeeAddress, linkOpts);
    
    \u transEmployeeA=新的TransformBlock((输入)=>
    {
    返回新的BaseMsg()
    {
    Id=input.Id,
    系统=输入。系统,
    Name=string.Concat(input.Forename,“,input.lasname),
    年龄=输入。年龄,
    地址=string.Concat(input.Number,“,input.Street),
    邮政编码=输入。邮政编码
    };
    });
    _transEmployeeB=新TransformBlock((输入)=>
    {
    返回新的BaseMsg()
    {
    Id=input.Id,
    系统=输入。系统,
    Name=input.Name,
    年龄=输入。年龄,
    地址=输入。地址,
    邮政编码=输入。邮政编码
    };
    });
    _broadcastBaseMsg=新的广播块(空);
    _transEmployeeName=新TransformBlock((baseMsg)=>
    {
    返回新的EmployeeName()
    {
    System=baseMsg.System,
    LegacyId=baseMsg.Id,
    Name=baseMsg.Name
    };
    });
    _transEmployeeAge=新TransformBlock((baseMsg)=>
    {
    返回新员工年龄()
    {
    System=baseMsg.System,
    LegacyId=baseMsg.Id,
    Age=baseMsg.Age
    };
    });
    _transEmployeeAddress=新TransformBlock((baseMsg)=>
    {
    返回新员工地址()
    {
    System=baseMsg.System,
    LegacyId=baseMsg.Id,
    地址=baseMsg.Address,
    Postcode=baseMsg.Postcode
    };
    });
    _bufferEmployeeName=新的BufferBlock();
    _bufferEmployeeAge=新的BufferBlock();
    _bufferEmployeeAddress=新的BufferBlock();
    _actionEmployeeName=新操作块((输出)=>
    {
    使用(var cxt=new SandboxContext())
    {
    cxt.EmployeeNames.Add(输出);
    cxt.SaveChanges();
    }
    });
    _actionEmployeeAge=新操作块((输出)=>
    {                
    使用(var cxt=new SandboxContext())
    {
    cxt.EmployeeAges.Add(输出);
    cxt.SaveChanges();
    }                
    });
    _actionEmployeeAddress=新操作块((输出)=>
    {                
    使用(var cxt=new SandboxContext())
    {
    cxt.EmployeeAddresses.Add(输出);
    cxt.SaveChanges();
    }               
    });
    var linkOpts=新数据流链接选项()
    {
    完成=真
    };
    //对员工进行改造并传递给批处理
    _transEmployeeA.LinkTo(_broadcastBaseMsg,linkOpts);
    _transEmployeeB.LinkTo(_broadcastBaseMsg,linkOpts);
    //将广播转换为各自的输出
    _broadcastbasemg.LinkTo(_transEmployeeName,linkOpts);
    _broadcastbasemg.LinkTo(_transEmployeeAge,linkOpts);
    _broadcastbasemg.LinkTo(_transEmployeeAddress,linkOpts);
    //将输出添加到缓冲区
    _transEmployeeName.LinkTo(_bufferEmployeeName,linkOpts);
    _transEmployeeAge.LinkTo(_bufferEmployeeAge,linkOpts);
    _transEmployeeAddress.LinkTo(_bufferEmployeeAddress,linkOpts);
    //将输出持久化到数据库
    _bufferEmployeeName.LinkTo(_actionEmployeeName,linkOpts);
    _bufferEmployeeAge.LinkTo(_actionEmployeeAge,linkOpts);
    _bufferEmployeeAddress.LinkTo(_actionEmployeeAddress,linkOpts);
    
    另外@TheodorZoulias的评论有助于简化我对TPL的使用